#专题练习# 最短路练习

最短路练习

 

0. Til the Cows Come Home  POJ - 2387  

完美的模板题

 1 //#include<Windows.h>
 2 #include<iostream>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<cstdio>
 6 #include<queue>
 7 using namespace std;
 8 const int MAX_V = 10005;
 9 const int MAX_E = 20010;
10 const int inf = 0x3f3f3f3f;
11 
12 struct ENode
13 {
14     int to;
15     int Next;
16     int w;
17 };
18 ENode Edegs[MAX_E];
19 int Head[MAX_V];
20 int Dis[MAX_V];
21 int tnt;
22 void Add_ENode(int u, int v, int w)
23 {
24     ++tnt;
25     Edegs[tnt].to = v;
26     Edegs[tnt].w = w;
27     Edegs[tnt].Next = Head[u];
28     Head[u] = tnt;
29     ++tnt;
30     Edegs[tnt].to = u;
31     Edegs[tnt].w = w;
32     Edegs[tnt].Next = Head[v];
33     Head[v] = tnt;
34 }
35 struct cmpx
36 {
37     bool operator () (int &a, int &b) const
38     {
39         return Dis[a] - Dis[b] > 0;
40     }
41 };
42 
43 void Dijkstra(int x)
44 {
45     priority_queue<int, vector<int>, cmpx> q;
46     memset(Dis, inf, sizeof(Dis));
47     Dis[x] = 0;
48     q.push(x);
49     while (!q.empty())
50     {
51         int u = q.top();
52         q.pop();
53         for (int k = Head[u]; k != -1; k= Edegs[k].Next)
54         {
55             int v = Edegs[k].to;
56             if (Dis[v] > Dis[u] + Edegs[k].w)
57             {
58                 Dis[v] = Dis[u] + Edegs[k].w;
59                 q.push(v);
60             }
61         }
62     }
63 }
64 
65 int main()
66 {
67     int t, n;
68     cin >> t >> n;
69     tnt = -1;
70     int a, b, w;
71     memset(Head, -1, sizeof(Head));
72     for (int i = 0; i < t; i++)
73     {
74         cin >> a >> b >> w;
75         Add_ENode(a, b, w);
76     }
77     Dijkstra(1);
78     cout << Dis[n] << endl;
79 //    system("pause");
80     return 0;
81 }
View Code

 

1. Frogger POJ - 2253  

青蛙和石头。在池塘里有2只青蛙和n块石头,石头之间有一定距离,现在一只(腿短的)青蛙想要去找另一只青蛙yuehui;给出n块石头的坐标,1号为男主青蛙所在的石头,二号为目标石头。他想尽可能的省力,每次都跳的尽量短。问它在所有可行路径中单次跳跃需要的最长距离的最小值是多少?

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<queue>
 6 #include<cmath>
 7 using namespace std;
 8 const int MAX_V= 210;
 9 const double inf= 99999999999999999.0;
10 typedef pair<double, double> _pair;
11 _pair rock[MAX_V];
12 double get_dis(_pair a, _pair b)
13 {
14     return sqrt(((a.first- b.first)* (a.first- b.first) )+ ((a.second- b.second)* (a.second- b.second) ) );
15 }
16 double Dis[MAX_V];
17 struct cmpx
18 {
19     bool operator() (int &a, int &b) const
20     {
21         return Dis[a]- Dis[b]> 0; 
22     }
23 };
24 int Front[MAX_V];
25 void Dijkstra(int n)
26 {
27     priority_queue<int, vector<int>, cmpx> q;
28     fill(Dis, Dis+ n+ 1, inf);
29     //for(int i= 1; i<= n; i ++) printf("%f\n", Dis[2]);
30     Dis[1]= 0;
31     Front[1]= -1;
32     q.push(1);
33     while (! q.empty() )
34     {
35         int u= q.top();
36         q.pop();
37         for (int i= 2; i<= n; i ++)
38         {
39             if (i== u) continue;
40             double detmp= get_dis(rock[u], rock[i]);
41             //printf("%f---%f---%f\n", Dis[u], detmp, Dis[i]);
42             if (Dis[i]> Dis[u]&& Dis[i]> detmp)
43             {
44                 Dis[i]= max(Dis[u], detmp);
45                 Front[i]= u;
46                 q.push(i);
47             }
48             //printf("%f\n", Dis[i]);
49         }
50     }
51 }
52 int main()
53 {
54     int n;
55     int t= 0;
56     while (cin >> n)
57     {
58         ++ t;
59         if (n== 0) break;
60         for (int i= 1; i<= n; i ++)
61         {
62             cin >> rock[i].first >> rock[i].second;
63         }
64         //for(int i= 2; i<= n; i ++) printf("%f\n", get_dis(rock[1], rock[i]));
65         Dijkstra(n);
66         printf("Scenario #%d\n",t);
67         printf("Frog Distance = %.3f\n\n", Dis[2]);
68         double ans= -1.0;
69         /*for (int c= n; c!= 1; c= Front[c])
70         {
71             double cnp= get_dis(rock[c], rock[Front[c]]);
72             ans= max(ans, cnp);
73         }
74         printf("Frog Distance = %.3f\n\n", ans);*/
75     }
76     return 0;
77 }
View Code

 

2. Heavy Transportation POJ - 1797  

城市中有N个路口,M个街道,每条街道都有最大承重限制;现在我们想要驾车从1号路口到N号路口,那么运输车所允许的最大重量是多少?

(不知道为什么老是PE,懒得改了)

 1 #include<algorithm>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<queue>
 6 using namespace std;
 7 const int maxv= 100010;
 8 const int maxe= 2100010;
 9 const int inf= 0x3f3f3f3f;
10 
11 struct ENode
12 {
13     int to;
14     int w;
15     int Next;
16 };
17 ENode edegs[maxe];
18 int Head[maxv], tnt;
19 void init()
20 {
21     memset(Head, -1, sizeof(Head));
22     tnt= -1;
23 }
24 void Add_ENode(int a, int b, int w)
25 {
26     ++ tnt;
27     edegs[tnt].to= b;
28     edegs[tnt].w= w;
29     edegs[tnt].Next= Head[a];
30     Head[a]= tnt;
31     ++ tnt;
32     edegs[tnt].to= a;
33     edegs[tnt].w= w;
34     edegs[tnt].Next= Head[b];
35     Head[b]= tnt;
36 }
37 
38 int dis[maxv];
39 struct cmpx
40 {
41     bool operator() (int &a, int &b) const
42     {
43         return dis[a]- dis[b]< 0;
44     }
45 };
46 void Dijkstra(int x)
47 {
48     priority_queue<int, vector<int>, cmpx> q;
49     memset(dis, 0, sizeof(dis));
50     dis[x]= inf;
51     q.push(x);
52 
53     while (! q.empty())
54     {
55         int u= q.top();
56         q.pop();
57         for (int k= Head[u]; k!= -1; k= edegs[k].Next)
58         {
59             int v= edegs[k].to;
60             if (dis[v]< min(dis[u], edegs[k].w))
61             {
62                 dis[v]= min(dis[u], edegs[k].w);
63                 q.push(v);
64             }
65         }
66     }
67 }
68 
69 int main()
70 {
71     int t, Case= 0;
72     int n, m;
73     scanf("%d", &t);
74     while (t --)
75     {
76         ++ Case;
77         scanf("%d %d", &n, &m);
78         init();
79         int a, b, w;
80         for (int i= 0; i< m; i ++)
81         {
82             scanf("%d %d %d", &a, &b, &w);
83             Add_ENode(a, b, w);
84         }
85         Dijkstra(1);
86         printf("Scenario #%d:\n%d\n", Case, dis[n]);
87     }
88     return 0;
89 }
View Code

 

 

3. Travel (The 2019 ACM-ICPC China Shannxi Provincial Programming Contest M)  /**计蒜客复现赛:点这里*/

星系中有n 个星球,编号从1 到N。星球之间有M个隧道相连,每个隧道都有一个长度。你有一个航天器,航天器有两个属性:传输距离d 和传输次数e 。航天器只能通过短于或等于其传输距离的通道;如果传输次数耗尽,则无法再使用航天器。航天器具有等级,lv0的航天器d 和e 都等于0,你可以给你的航天器升级,每次升级都会消耗c 点花费,给你的航天器提升dx和 ex点属性。现在,告诉你n,m,m条通道的信息,还有给你的航天器升级时的c,dx,ex。

Q: 你能求出从1 到N 的最小花费吗?

A: 把原本记录到达此点最短距离的Dis[] 变成 记录到达此点所需要飞行器最低等级的Dis_Level[],这样剩下的就是普通的Dijkstra了。

 1 #include<algorithm>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<queue>
 5 using namespace std;
 6 const int MAX_V= 100010;
 7 const int MAX_E= 400010;
 8 const int inf= 0x3f3f3f3f;
 9 
10 struct ENode
11 {
12     int to;
13     int w;
14     int Next;
15 };
16 ENode edegs[MAX_E];
17 int Head[MAX_V], tnt;
18 void Add_ENode(int a, int b, int w)
19 {
20     edegs[++ tnt].to= b;
21     edegs[tnt].w= w;
22     edegs[tnt].Next= Head[a];
23     Head[a]= tnt;
24     edegs[++ tnt].to= a;
25     edegs[tnt].w= w;
26     edegs[tnt].Next= Head[b];
27     Head[b]= tnt;
28 }
29 
30 int Dis_Level[MAX_V];  //到每个点,所需要的飞船最小等级;
31 int deep[MAX_V];  //每个点bfs 的深度;
32 struct cmpx
33 {
34     bool operator() (int &a, int &b) const
35     {
36         return Dis_Level[a]- Dis_Level[b]> 0;
37     }
38 };
39 void Dijkstra(int x, int _dis, int _cost)
40 {
41     /*x为起点, _dis是每次升级提升的传送距离, _cost是升级提升的传送次数;*/
42     memset(Dis_Level, inf, sizeof(Dis_Level));
43     memset(deep, inf, sizeof(deep));
44     priority_queue<int, vector<int>, cmpx> q;
45     Dis_Level[x]= 0; //起点的飞行器等级为0;
46     deep[x]= 0;  //起点深度为0;
47     q.push(x);
48     while (! q.empty())
49     {
50         int u= q.top();
51         q.pop();
52         for (int k= Head[u]; k!= -1; k= edegs[k].Next)
53         {
54             int v= edegs[k].to;
55             int lev_tmp= Dis_Level[u];
56             while (lev_tmp* _dis< edegs[k].w|| lev_tmp* _cost< deep[u]+ 1)
57             {
58                 /*若当前的飞行器等级不能穿越此隧道,或传送次数已用完,则升级飞行器一次;*/
59                 lev_tmp ++;
60             }
61             if (lev_tmp< Dis_Level[v])
62             {
63                 /*如果此时的飞行器等级小与之前到达点v 的飞行器等级,则更新Dis_Level[v]*/
64                 Dis_Level[v]= lev_tmp;
65                 deep[v]= deep[u]+ 1; //深度也要 +1;
66                 q.push(v); //加入队列;
67             }
68         }
69     }
70 }
71 void into()
72 {
73     memset(Head, -1, sizeof(Head));
74     tnt= -1;
75 }
76 
77 int main()
78 {
79     int n, m;
80     int c, d, e;
81     int a, b ,w;
82     while (~ scanf("%d %d", &n, &m))
83     {
84         scanf("%d %d %d", &c, &d, &e);
85         into();
86         for (int i= 0;i< m;i ++)
87         {
88             scanf("%d %d %d", &a, &b, &w);
89             Add_ENode(a, b, w);
90         }
91         Dijkstra(1, d, e);
92         if (Dis_Level[n]== inf) printf("-1\n");
93         else printf("%lld\n", (long long)Dis_Level[n]* c);
94     }
95     return 0;
96 }
View Code

 

4.Marriage Match IV (HDU 3416)

Starvae在A市,女孩在B市。每次starvae都可以到达B市并与他喜欢的女孩一起xoxo。但是他面前有两个问题,一是starvae必须在最短的时间内到达B,所以说他必须选择最短的路径;二是每条道路只能走一次,但每座城市他可以经过多次。那么,请你告诉他:从A-->B的(完全不同的)最短路径一共有几条?

Ps:最短路径+最大流。先用Dijkstra求出A到B的最短路径并处理dis[]数组,然后依照条件(dis[v]== dis[u]+ edegs[k].w)找出所有在最短路径上的边,并建一个图2。随后就是Dinic跑最大流出结果,代码如下。

  1 #include<algorithm>
  2 #include<iostream>
  3 #include<cstring>
  4 #include<cstdio>
  5 #include<queue>
  6 using namespace std;
  7 const int maxv= 1010;
  8 const int maxe= 400010;
  9 const int inf= 0x3f3f3f3f;
 10 
 11 struct ENode
 12 {
 13     int to;
 14     int w;
 15     int Next;
 16 };
 17 ENode edegs[maxe];
 18 int Head[maxv], tnt;
 19 void init()
 20 {
 21     memset(Head, -1, sizeof(Head));
 22     tnt= -1;
 23 }
 24 void Add_ENode(int a, int b, int w)
 25 {
 26     ++ tnt;
 27     edegs[tnt].to= b;
 28     edegs[tnt].w= w;
 29     edegs[tnt].Next= Head[a];
 30     Head[a]= tnt;
 31 }
 32 
 33 int dis[maxv];
 34 struct cmpx
 35 {
 36     bool operator() (int &a, int &b) const
 37     {
 38         return dis[a]- dis[b]> 0;
 39     }
 40 };
 41 void Dijkstra(int x)
 42 {
 43     priority_queue<int, vector<int>, cmpx> q;
 44     memset(dis, inf, sizeof(dis));
 45     dis[x]= 0;
 46     q.push(x);
 47 
 48     while (! q.empty())
 49     {
 50         int u= q.top();
 51         q.pop();
 52 
 53         for (int k= Head[u]; k!= -1; k= edegs[k].Next)
 54         {
 55             int v=  edegs[k].to;
 56             if (dis[v]> dis[u]+ edegs[k].w )
 57             {
 58                 dis[v]= dis[u]+ edegs[k].w;
 59                 q.push(v);
 60             }
 61         }
 62     }
 63 }
 64 
 65 /*建新图,跑最大流*/
 66 ENode edegs1[maxe];
 67 int Head1[maxv], tnt1;
 68 void init1()
 69 {
 70     memset(Head1, -1, sizeof(Head1));
 71     tnt1= -1;
 72 }
 73 void Add_ENode1(int a, int b, int w)
 74 {
 75     ++ tnt1;
 76     edegs1[tnt1].to= b;
 77     edegs1[tnt1].w= w;
 78     edegs1[tnt1].Next= Head1[a];
 79     Head1[a]= tnt1;
 80     ++ tnt1;
 81     edegs1[tnt1].to= a;
 82     edegs1[tnt1].w= 0;
 83     edegs1[tnt1].Next= Head1[b];
 84     Head1[b]= tnt1;
 85 }
 86 void Dijk2(int n)
 87 {
 88     init1();
 89     for (int u= 1; u<= n; u ++)
 90     {
 91         for (int k= Head[u]; k!= -1; k= edegs[k].Next)
 92         {
 93             int v=  edegs[k].to;
 94             if (dis[v]== dis[u]+ edegs[k].w )
 95             {
 96                 Add_ENode1(u, v, 1);
 97             }
 98         }
 99     }
100 }
101 int level[maxv];
102 bool bfs_level (int s, int t)
103 {
104     memset(level, -1, sizeof(level)); //所有点的等级初始化为-1;
105     level[s]= 1; //源点的等级为1;
106     int que[maxv];  //队列que:按序保存已搜索到的点;
107     int iq= 0;
108     que[iq ++]= s; //先将源点s 加入队列;
109     for (int i= 0; i< iq; i ++)
110     {
111         int u= que[i];  //取出队首元素;
112         if (u== t)
113         {
114             /*找到汇点t,返回*/
115             return true;
116         }
117         for (int k= Head1[u]; k!= -1; k= edegs1[k].Next)
118         {
119             /*遍历,查找到之前未找到的、可抵达的点便加入队列*/
120             int v= edegs1[k].to;
121             if (-1== level[v]&& edegs1[k].w)
122             {
123                 level[v]= level[u]+ 1; //深度 +1;
124                 que[iq ++]= v;
125             }
126         }
127     }
128     return false;
129 }
130 int dfs(int now, int c_max, int t)
131 {
132     /**DFS 实现多路增广*/
133     /*now:起点;c_max:从源点s到节点now的最大流量;t:汇点、dfs结束的终点*/
134     if (now== t) return c_max; //当now== t时,c_max便是要求的最大流;
135     int ret= 0, f;
136     for (int k= Head1[now]; k!= -1; k= edegs1[k].Next)
137     {
138         if (edegs1[k].w&& level[edegs1[k] .to]== level[now]+ 1)
139         {
140             /**/
141             f= dfs(edegs1[k].to, min(c_max- ret, edegs1[k].w), t);
142             edegs1[k].w-= f;
143             edegs1[k^1].w+= f;
144             ret+= f;
145             if(ret== c_max) return ret;
146         }
147     }
148     return ret;
149 }
150 int dinic(int s, int t)
151 {
152     int ans= 0;
153     while(bfs_level(s, t))
154     {
155         ans+= dfs(s, inf, t);
156     }
157     return ans;
158 }
159 
160 int main()
161 {
162     int t;
163     int n, m;
164     scanf("%d", &t);
165     while (t --)
166     {
167         scanf("%d %d", &n, &m);
168         init();
169         int a, b, w;
170         for (int i= 0; i< m; i ++)
171         {
172             scanf("%d %d %d", &a, &b, &w);
173             Add_ENode(a, b, w);
174         }
175         int start, endd;
176         scanf("%d %d", &start, &endd);
177         Dijkstra(start);
178         Dijk2(n);
179         int ans= dinic(start, endd);
180         printf("%d\n", ans);
181     }
182     return 0;
183 }
View Code

 

 

 

end;

posted @ 2019-05-26 19:20  egoist的翻绳游戏  阅读(207)  评论(0编辑  收藏  举报