[关闭]
@Metralix 2018-03-08T14:25:23.000000Z 字数 7205 阅读 763

寒假训练 DIV1(3)最短路及其应用1


A - Airport Express

最短路


题目大意

某个人要从起点到终点, 有m个经济站和k个商业站, 只能乘坐一次商业站, 求最短时间。

解题思路

因为多了商业站, 所以不能直接套用最短路, 但是注意到只有一次乘坐商业站的机会, 所以直接枚举坐哪个商业站就行了, 这样,其他部分就是最短路了, 假设商业站是从a到b,花费c,那么答案就是d1[a] + d2[b] + c, d1是从起点的最短路,d2是从终点出发的最短路。
  1. #include<map>
  2. #include<queue>
  3. #include<stack>
  4. #include<cmath>
  5. #include<ctime>
  6. #include<cctype>
  7. #include<string>
  8. #include<cstdio>
  9. #include<cstring>
  10. #include<iostream>
  11. #include<algorithm>
  12. using namespace std;
  13. typedef long long ll;
  14. const int maxv = 500 + 5;
  15. const int max_dis = 999999999;
  16. struct Edge{
  17. int to;
  18. int dis;
  19. Edge(int to,int dis){
  20. this -> to = to;
  21. this -> dis = dis;
  22. }
  23. };
  24. int N,S,E,M,K;
  25. int X,Y,Z,cases=0;
  26. vector<Edge>G[maxv];
  27. int Sdis[maxv],Edis[maxv];
  28. int Shead[maxv],Ehead[maxv];
  29. int path[maxv],ans,Start,End,cnt;
  30. typedef pair<int,int>P;
  31. void init(){
  32. Start=-1; cnt=0;
  33. for(int i=0;i<maxv;i++) G[i].clear();
  34. memset(Shead,-1,sizeof(Shead));
  35. memset(Ehead,-1,sizeof(Ehead));
  36. fill(Sdis+1,Sdis+1+N,max_dis);
  37. fill(Edis+1,Edis+1+N,max_dis);
  38. }
  39. void dijkstra(int dis[],int head[],int s){
  40. priority_queue<P,vector<P>,greater<P> >q;
  41. while(!q.empty()) q.pop();
  42. dis[s]=0;
  43. q.push(P(0,s));
  44. while(!q.empty()){
  45. P p=q.top(); q.pop();
  46. int v=p.second;
  47. if(p.first>dis[v]) continue;
  48. for(int i=0;i<G[v].size();i++){
  49. Edge& e=G[v][i];
  50. if(dis[v]+e.dis<dis[e.to]){
  51. head[e.to]=v;
  52. dis[e.to]=dis[v]+e.dis;
  53. q.push(P(dis[e.to],e.to));
  54. }
  55. }
  56. }
  57. }
  58. void doit(){
  59. dijkstra(Sdis,Shead,S);
  60. dijkstra(Edis,Ehead,E);
  61. ans=Sdis[E];
  62. }
  63. int main(){
  64. while(scanf("%d%d%d",&N,&S,&E)!=EOF){
  65. init();
  66. scanf("%d",&M);
  67. for(int i=0;i<M;i++){
  68. scanf("%d%d%d",&X,&Y,&Z);
  69. G[X].push_back(Edge(Y,Z));
  70. G[Y].push_back(Edge(X,Z));
  71. }
  72. doit();
  73. scanf("%d",&K);
  74. for(int i=0;i<K;i++){
  75. scanf("%d%d%d",&X,&Y,&Z);
  76. if(Sdis[X]+Edis[Y]+Z<ans){
  77. Start=X; End=Y;
  78. ans=Sdis[X]+Edis[Y]+Z;
  79. }
  80. if(Sdis[Y]+Edis[X]+Z<ans){
  81. Start=Y; End=X;
  82. ans=Sdis[Y]+Edis[X]+Z;
  83. }
  84. }
  85. if(cases) printf("\n");
  86. cases++;
  87. if(Start==-1){
  88. for(int i=E;i!=-1;i=Shead[i]) path[cnt++]=i;
  89. for(int i=cnt-1;i>=0;i--){
  90. if(i==0) printf("%d\n",path[i]);
  91. else printf("%d ",path[i]);
  92. }
  93. printf("Ticket Not Used\n%d\n",ans);
  94. }
  95. else{
  96. for(int i=Start;i!=-1;i=Shead[i]) path[cnt++]=i;
  97. reverse(path,path+cnt);
  98. for(int i=End;i!=-1;i=Ehead[i]) path[cnt++]=i;
  99. for(int i=0;i<cnt;i++){
  100. if(i==cnt-1) printf("%d\n",path[i]);
  101. else printf("%d ",path[i]);
  102. }
  103. printf("%d\n%d\n",Start,ans);
  104. }
  105. }return 0;
  106. }

B - Walk Through the Forest

标签: dijkstra


题目大意

只走(A,B):存在一条从B出发回家的路,比所有从A出发回家的路径都短。问这样的路径有几条。

解题思路

先反向求一遍最短路,得到d数组。当d[B] < d[A]时,满足(A,B)路径,这样就能容易找到(A,B)路径,DFS找一遍总路径数就好了。
  1. #include<stdio.h>
  2. #include<string.h>
  3. #include<iostream>
  4. using namespace std;
  5. #define MAXN 1005
  6. int cost[MAXN][MAXN];
  7. int dis[MAXN];
  8. int sum[MAXN];
  9. #define INF 0x3f3f3f3f
  10. #define typec int
  11. int path[MAXN],vis[MAXN];
  12. void Dijkstra(typec cost[][MAXN],typec lowcost[MAXN],int n,int beg)
  13. {
  14. int i,j;
  15. typec minc;
  16. memset(vis,0,sizeof(vis));
  17. vis[beg]=1;
  18. for(i=1;i<=n;i++)
  19. {
  20. lowcost[i]=cost[beg][i];path[i]=beg;
  21. }
  22. lowcost[beg]=0;
  23. path[beg]=-1;//树根的标记
  24. int pre;
  25. for(int num=2;num<n;num++)
  26. {
  27. minc=INF;
  28. for(j=1;j<=n;j++)
  29. if(vis[j]==0&&lowcost[j]<minc)
  30. {pre=j;minc=lowcost[j];}
  31. if(minc>=INF)break;
  32. vis[pre]=1;
  33. for(j=1;j<=n;j++)
  34. if(vis[j]==0&&lowcost[pre]+cost[pre][j]<lowcost[j])
  35. {lowcost[j]=lowcost[pre]+cost[pre][j];path[j]=pre;}
  36. }
  37. }
  38. int dfs(int i,int n)
  39. {
  40. if(i==2) return 1;
  41. if(sum[i]!=-1) return sum[i];
  42. int cnt=0;
  43. for(int j=1;j<=n;j++)
  44. {
  45. if(cost[i][j]<INF&&dis[j]<dis[i])
  46. cnt+=dfs(j,n);
  47. }
  48. sum[i]=cnt;
  49. return sum[i];
  50. }
  51. int main()
  52. {
  53. int i,j;
  54. int n,m;
  55. int a,b,d;
  56. while(scanf("%d",&n),n)
  57. {
  58. scanf("%d",&m);
  59. for(i=1;i<=n;i++)
  60. for(j=1;j<=n;j++)
  61. {
  62. if(i==j)cost[i][j]=0;
  63. else cost[i][j]=INF;
  64. }
  65. while(m--)
  66. {
  67. scanf("%d%d%d",&a,&b,&d);
  68. cost[a][b]=d;
  69. cost[b][a]=d;
  70. }
  71. Dijkstra(cost,dis,n,2);
  72. memset(sum,-1,sizeof(sum));
  73. printf("%d\n",dfs(1,n));
  74. }
  75. }

C - Warfare And Logistics

标签: 最短路


题目大意

 给出一个n节点m条边的无向图,每条边上有一个正权,令c等于每对结点的最短路径之和,要求删除一条边后使得新的c值最大,不连通的两个点距离视为L

解题思路

每次求单源最短路的同时记录下删除边的值,然后计算最小值就是了
  1. #include<cstdio>
  2. #include<cstring>
  3. #include<queue>
  4. #include<vector>
  5. #include<algorithm>
  6. #define FOR(a,b,c) for(int a=(b);a<=(c);a++)
  7. using namespace std;
  8. const int maxn = 100+10,maxm=1000+10;
  9. const int INF=1e9;
  10. struct Edge{
  11. int u,v,w,next;
  12. };
  13. int n,m,L;
  14. struct SPFA{
  15. int n;
  16. Edge e[2*maxm];
  17. int en,front[maxn];
  18. int inq[maxn],d[maxn];
  19. int p[maxn];
  20. queue<int> q;
  21. void init(int n){
  22. this->n=n;
  23. en=-1;
  24. memset(front,-1,sizeof(front));
  25. }
  26. void AddEdge(int u,int v,int w) {
  27. en++; e[en].u=u; e[en].v=v; e[en].w=w; e[en].next=front[u]; front[u]=en;
  28. }
  29. void solve(int s) {
  30. memset(inq,0,sizeof(inq));
  31. memset(p,0,sizeof(p));
  32. for(int i=1;i<=n;i++) d[i]=INF;
  33. d[s]=0; inq[s]=1; q.push(s);
  34. while(!q.empty()) {
  35. int u=q.front(); q.pop(); inq[u]=0;
  36. for(int i=front[u];i>=0;i=e[i].next) {
  37. int v=e[i].v,w=e[i].w;
  38. if(w>0 && d[v]>d[u]+w) {
  39. d[v]=d[u]+w;
  40. p[v]=i;
  41. if(!inq[v]) {
  42. inq[v]=1;
  43. q.push(v);
  44. }
  45. }
  46. }
  47. }
  48. }
  49. }spfa;
  50. vector<int> gr[maxn][maxn];
  51. int idx[maxn][maxn];
  52. int used[maxn][maxn][maxn];
  53. int sum_single[maxn];
  54. int CALC_C() {
  55. int ans=0;
  56. memset(used,0,sizeof(used));
  57. FOR(scr,1,n)
  58. {
  59. spfa.solve(scr);
  60. sum_single[scr]=0;
  61. FOR(v,1,n)
  62. {
  63. if(v!=scr) {
  64. int u=spfa.e[spfa.p[v]].u;
  65. used[scr][u][v]=used[scr][v][u]=1;
  66. }
  67. sum_single[scr] += spfa.d[v]==INF? L : spfa.d[v];
  68. }
  69. ans += sum_single[scr];
  70. }
  71. return ans;
  72. }
  73. int CALC_C2(int a,int b) {
  74. int ans=0;
  75. FOR(scr,1,n)
  76. {
  77. if(!used[scr][a][b]) ans+=sum_single[scr];
  78. else
  79. {
  80. spfa.solve(scr);
  81. FOR(v,1,n) ans += spfa.d[v]==INF?L: spfa.d[v];
  82. }
  83. }
  84. return ans;
  85. }
  86. int main()
  87. {
  88. while(scanf("%d%d%d",&n,&m,&L)==3)
  89. {
  90. int u,v,w;
  91. spfa.init(n);
  92. FOR(i,1,n) FOR(j,1,n) gr[i][j].clear();
  93. while(m--) {
  94. scanf("%d%d%d",&u,&v,&w);
  95. gr[u][v].push_back(w);
  96. gr[v][u].push_back(w);
  97. }
  98. FOR(i,1,n) FOR(j,i+1,n) if(!gr[i][j].empty()){
  99. sort(gr[i][j].begin(),gr[i][j].end());
  100. spfa.AddEdge(i,j,gr[i][j][0]);
  101. idx[i][j]=spfa.en;
  102. spfa.AddEdge(j,i,gr[i][j][0]);
  103. idx[j][i]=spfa.en;
  104. }
  105. int c=CALC_C(),c2=-1;
  106. FOR(i,1,n) FOR(j,i+1,n) if(!gr[i][j].empty()){
  107. int& e1=spfa.e[idx[i][j]].w;
  108. int& e2=spfa.e[idx[j][i]].w;
  109. if(gr[i][j].size()==1) e1=e2=-1;
  110. else e1=e2=gr[i][j][1];
  111. c2=max(c2,CALC_C2(i,j));
  112. e1=e2=gr[i][j][0];
  113. }
  114. printf("%d %d\n",c,c2);
  115. }
  116. return 0;
  117. }

D - The Toll! Revisited

标签: dijstra


题目大意

  给定一个无向图,大写字母是城市,小写字母是村庄,经过城市交过路费为当前货物的%5,路过村庄固定交1,给定起点终点和到目标地点要剩下的货物,问最少要带多少货物上路,并输出路径,如果有多种方案,要求字典序最小

解题思路

 dijstra的逆向运用,d数组含义变成到该结点至少需要这么多货物,然后反向建图,从终点向起点反向做一遍
  1. #include <cstdio>
  2. #include <cstring>
  3. #include <vector>
  4. #include <queue>
  5. #include <algorithm>
  6. using namespace std;
  7. typedef long long ll;
  8. const int maxn = 55;
  9. const int inf = 0x3f3f3f3f;
  10. int IDX(char ch) { if (ch >= 'A' && ch <= 'Z') return ch - 'A'; else return 26 + ch - 'a'; }
  11. char RIDX(int x) { if (x < 26) return 'A' + x; else return 'a' + x - 26; }
  12. int N = 52, M, S, E, L, V[maxn];
  13. ll D[maxn];
  14. vector<int> G[maxn], ans;
  15. struct State {
  16. int u;
  17. ll d;
  18. State (int u = 0, ll d = 0): u(u), d(d) {}
  19. bool operator < (const State& u) const { return d > u.d; }
  20. };
  21. void init () {
  22. for (int i = 0; i <= N; i++) G[i].clear();
  23. char s[5], e[5];
  24. for (int i = 0; i < M; i++) {
  25. scanf("%s%s", s, e);
  26. int u = IDX(s[0]), v = IDX(e[0]);
  27. G[u].push_back(v);
  28. G[v].push_back(u);
  29. }
  30. scanf("%d%s%s", &L, s, e);
  31. S = IDX(s[0]), E = IDX(e[0]);
  32. }
  33. ll limit (int x, ll w) {
  34. if (x >= 26) return w+1;
  35. ll l = 0, r = inf;
  36. while (l < r) {
  37. ll mid = (l + r) >> 1;
  38. ll t = mid + w;
  39. if (t - (t + 19) / 20 >= w) r = mid;
  40. else l = mid + 1;
  41. }
  42. return w + l;
  43. }
  44. ll consume(int u, ll d) {
  45. if (u >= 26) return 1;
  46. else return (d + 19) / 20;
  47. }
  48. void put (int u) {
  49. ans.push_back(u);
  50. if (u == E) return;
  51. int rec = -1;
  52. for (int i = 0; i < G[u].size(); i++) {
  53. int v = G[u][i];
  54. if (D[u] - consume(v, D[u]) == D[v] && (rec == -1 || rec > v))
  55. rec = v;
  56. }
  57. put(rec);
  58. }
  59. void dijkstra () {
  60. memset(V, 0, sizeof(V));
  61. memset(D, inf, sizeof(D));
  62. D[E] = L;
  63. priority_queue<State> Q;
  64. Q.push(State(E, D[E]));
  65. while (!Q.empty()) {
  66. int u = Q.top().u;
  67. Q.pop();
  68. if (V[u]) continue;
  69. V[u] = 1;
  70. ll w = limit(u, D[u]);
  71. for (int i = 0; i < G[u].size(); i++) {
  72. int v = G[u][i];
  73. if (D[v] > w) {
  74. D[v] = w;
  75. Q.push(State(v, w));
  76. }
  77. }
  78. }
  79. printf("%lld\n", D[S]);
  80. ans.clear();
  81. put(S);
  82. for (int i = 0; i < ans.size(); i++) {
  83. printf("%c%c", RIDX(ans[i]), i == ans.size()-1 ? '\n' : '-');
  84. }
  85. }
  86. int main () {
  87. int cas = 1;
  88. while (scanf("%d", &M) == 1 && M != -1) {
  89. init ();
  90. printf("Case %d:\n", cas++);
  91. dijkstra();
  92. }
  93. return 0;
  94. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注