最短路专题(不定期更新)

Posted 萌萌的美男子

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了最短路专题(不定期更新)相关的知识,希望对你有一定的参考价值。

1、Til the Cows Come Home  POJ 2387

  题意:找到从N到1的最短路径。

  思路:SPFA。

技术分享
 1 #include<iostream>
 2 #include<vector>
 3 #include<queue>
 4 using namespace std;
 5 const int maxn = 1010;
 6 const int INF = 0x7fffffff;
 7 int n, t;
 8 struct node
 9 {
10     int to;
11     int length;
12     node(int tt=0,int ll=0):to(tt),length(ll){ }
13 };
14 vector<node>mp[maxn];
15 int dis[maxn];
16 bool vis[maxn];
17 int cnt[maxn];
18 
19 bool SPFA(int root)
20 {
21     memset(vis, 0, sizeof(vis));
22     memset(cnt, 0, sizeof(cnt));
23     for (int i = 1; i <= n; i++) dis[i] = INF;
24     dis[root] = 0, cnt[root] = 1, vis[root] = true;
25     queue<int>q;
26     q.push(root);
27     while (!q.empty())
28     {
29         int u = q.front();
30         q.pop();
31         vis[u] = false;
32         int sz = mp[u].size();
33         for (int i = 0; i < sz; i++)
34         {
35             int v = mp[u][i].to,len = mp[u][i].length;
36             if (dis[u] + len < dis[v])
37             {
38                 dis[v] = dis[u] + len;
39                 if (!vis[v])
40                 {
41                     q.push(v);
42                     vis[v] = true;
43                     cnt[v]++;
44                     if (cnt[v] > n)return false;
45                 }
46             }
47         }
48     }
49     return true;
50 }
51 void Run()
52 {
53     for (int i = 0; i <= n; i++) mp[i].clear();
54     for (int i = 0; i < t; i++)
55     {
56         int u, v, l;
57         scanf("%d%d%d", &u, &v, &l);
58         mp[u].push_back(node(v, l));
59         mp[v].push_back(node(u, l));
60     }
61     SPFA(n);
62     printf("%d\n", dis[1]);
63 }
64 int main()
65 {
66     while (~scanf("%d%d", &t, &n))
67     {
68         Run();
69     }
70     return 0;
71 }
View Code

2、POJ 2253 Frogger

  题意:求从第一块石头到第二块石头的最大权值的最小值。

  思路:SPFA扩展,dis[j] = min(dis[j], max(dis[MinNum], len))。注意初始化。

技术分享
 1 //从1到2的路径所经过的最大权值的最小值
 2 #include<iostream>
 3 #include<cmath>
 4 #include<algorithm>
 5 using namespace std;
 6 const int maxn = 210;
 7 const double INF = 1e9;
 8 int n;
 9 double dis[maxn];
10 bool vis[maxn];
11 int pre[maxn];
12 double ans;
13 struct node
14 {
15     int x;
16     int y;
17 }stones[maxn];
18 void dijkstra(int start)
19 {
20     memset(vis, 0, sizeof(vis));
21     for (int i = 0; i < n; i++)
22         dis[i] = INF;
23     dis[start] = 0;
24     for (int i = 1; i <= n; i++)
25     {
26         int MinNum;
27         double Min = INF;
28         for (int j = 0; j < n; j++)
29             if (!vis[j] && dis[j]<Min)
30             {
31                 MinNum = j;
32                 Min = dis[j];
33             }
34         vis[MinNum] = true;
35         for (int j = 0; j < n; j++)
36         {
37             double len = sqrt(1.0*(stones[j].x - stones[MinNum].x)*(stones[j].x - stones[MinNum].x) + (stones[j].y - stones[MinNum].y)*(stones[j].y - stones[MinNum].y));
38             //dis[j] = min(dis[j], max(dis[MinNum], len));//dis[j]为从0号石头到第j号石头所有通路中最长边中的最小边
39             if (!vis[j]&&max(dis[MinNum], len) < dis[j]) dis[j] = max(dis[MinNum], len);
40         }
41     }
42 }
43 int main()
44 {
45     int Case = 1;
46     while (~scanf("%d", &n))
47     {
48         if (n == 0)break;
49         for (int i = 0; i < n; i++)
50         {
51             scanf("%d%d", &stones[i].x, &stones[i].y);
52         }
53         dijkstra(0);
54         printf("Scenario #%d\n", Case);
55         printf("Frog Distance = %.3lf\n\n", dis[1]);
56         Case++;
57     }
58     return 0;
59 }
View Code

3、poj 1797 Heavy Transportation

  题意:求1到n的路径的最小权值的最大值。

  思路:最短路拓展,dis[v] = max(dis[v],min(dis[u],len)).注意初始化。

技术分享
  1 //求1到n的路径的最小权值的最大值
  2 #include<iostream>
  3 #include<vector>
  4 #include<queue>
  5 #include<algorithm>
  6 using namespace std;
  7 const int maxn = 1010;
  8 const int INF = 0x7fffffff;
  9 int n, m,Case;
 10 struct node
 11 {
 12     int to;
 13     int length;
 14     node(int tt = 0, int ll = 0) :to(tt), length(ll)
 15     {
 16     }
 17 };
 18 vector<node>mp[maxn];
 19 int dis[maxn];
 20 bool vis[maxn];
 21 int cnt[maxn];
 22 int ans;
 23 bool SPFA(int root)
 24 {
 25     memset(vis, 0, sizeof(vis));
 26     memset(cnt, 0, sizeof(cnt));
 27     memset(dis, 0, sizeof(dis));
 28     dis[root] =INF, cnt[root] = 1, vis[root] = true;
 29     queue<int>q;
 30     q.push(root);
 31     while (!q.empty())
 32     {
 33         int u = q.front();
 34         q.pop();
 35         vis[u] = false;
 36         int sz = mp[u].size();
 37         for (int i = 0; i < sz; i++)
 38         {
 39             int v = mp[u][i].to, len = mp[u][i].length;
 40             if (min(dis[u],len) > dis[v])
 41             {
 42                 dis[v] = min(dis[u],len);
 43                 if (!vis[v])
 44                 {
 45                     q.push(v);
 46                     vis[v] = true;
 47                     cnt[v]++;
 48                     if (cnt[v] > n)return false;
 49                 }
 50             }
 51         }
 52     }
 53     return true;
 54 }
 55 void Dij(int root)
 56 {
 57     memset(vis, 0, sizeof(vis));
 58     memset(dis, 0, sizeof(dis));
 59     int sz = mp[root].size();
 60     for (int i = 0; i < sz; i++)
 61     {
 62         dis[mp[root][i].to] = mp[root][i].length;
 63     }
 64     vis[1] = true;//标记点1已经访问过  
 65     for (int i = 1; i <= n - 1; i++)
 66     {
 67         int maxx = 0,u=root;
 68         for (int j = 1; j <= n; j++)
 69         {
 70             if (!vis[j] && dis[j]>maxx)
 71             {
 72                 maxx = dis[j];
 73                 u = j;
 74             }
 75         }
 76         vis[u] = true;
 77         int sz = mp[u].size();
 78         for (int j = 0; j < sz; j++)
 79         {
 80             int v = mp[u][j].to;
 81             if (!vis[v] && dis[v] < min(dis[u],mp[u][j].length))
 82                 dis[v] = min(dis[u], mp[u][j].length);
 83         }
 84     }
 85 }
 86 void Run()
 87 {
 88     for (int i = 0; i <= n; i++) mp[i].clear();
 89     for (int i = 0; i < m; i++)
 90     {
 91         int u, v, l;
 92         scanf("%d%d%d", &u, &v, &l);
 93         mp[u].push_back(node(v, l));
 94         mp[v].push_back(node(u, l));
 95     }
 96     //SPFA(1);
 97     Dij(1);
 98     printf("Scenario #%d:\n", Case);
 99     printf("%d\n\n",dis[n]);
100 }
101 int main()
102 {
103     int C;
104     Case = 1;
105     scanf("%d", &C);
106     while (C--)
107     {
108         scanf("%d%d", &n, &m);
109         Run();
110         Case++;
111     }
112     return 0;
113 }
View Code

4、poj 3268 Silver Cow Party

  题意:每头牛从自己家最短路到X,再从X走最短路回家。求所有牛中走过距离的最大值。

  思路:对其他点求一次到X的最短路,再从X求一次到其他各点的最短路。

技术分享
 1 #include<iostream>
 2 #include<vector>
 3 #include<queue>
 4 using namespace std;
 5 const int maxn = 1010;
 6 const int INF = 0x7fffffff;
 7 int n, m,x;
 8 int sumdis[maxn];
 9 struct node
10 {
11     int to;
12     int length;
13     node(int tt = 0, int ll = 0) :to(tt), length(ll)
14     {
15     }
16 };
17 vector<node>mp[maxn];
18 int dis[maxn][maxn];
19 bool vis[maxn];
20 int cnt[maxn];
21 
22 bool SPFA(int root)
23 {
24     memset(vis, 0, sizeof(vis));
25     memset(cnt, 0, sizeof(cnt));
26     for (int i = 1; i <= n; i++) dis[root][i] = INF;
27     queue<int>q;
28     dis[root][root] = 0, vis[root] = true, cnt[root]++;
29     q.push(root);
30     while (!q.empty())
31     {
32         int u = q.front();
33         q.pop();
34         vis[u] = false;
35         int sz = mp[u].size();
36         for (int i = 0; i < sz; i++)
37         {
38             int v = mp[u][i].to, len = mp[u][i].length;
39             if (dis[root][u] + len < dis[root][v])
40             {
41                 dis[root][v] = dis[root][u] + len;
42                 if (!vis[v])
43                 {
44                     q.push(v);
45                     vis[v] = true;
46                     cnt[v]++;
47                     if (cnt[v] > n)return false;
48                 }
49             }
50         }
51     }
52     return true;
53 }
54 void Run()
55 {
56     for (int i = 0; i <= n; i++) mp[i].clear();
57     for (int i = 0; i < m; i++)
58     {
59         int u, v, l;
60         scanf("%d%d%d", &u, &v, &l);
61         mp[u].push_back(node(v, l));
62     }
63     int maxl=0;
64     for (int i = 1; i <= n; i++)
65     {
66         if (i == x)continue;
67         SPFA(i);
68         sumdis[i] = dis[i][x];
69     }
70     SPFA(x);
71     for (int i = 1; i <= n; i++)
72     {
73         if (i == x) continue;
74         sumdis[i] += dis[x][i];
75         maxl = max(maxl, sumdis[i]);
76     }
77     printf("%d\n",maxl);
78 }
79 int main()
80 {
81     while (~scanf("%d%d%d", &n, &m,&x))
82     {
83         Run();
84     }
85     return 0;
86 }
View Code

5、POJ 1860 Currency Exchange

  题意:给出货币之间的汇率兑换,问是否能经过几次兑换后,其得到的货币比原先要多。

  思路:SPFA判正环。

技术分享
 1 #include<iostream>
 2 #include<vector>
 3 #include<queue>
 4 using namespace std;
 5 const int maxn = 110;
 6 const int INF = 0x7fffffff;
 7 int n, m, s;
 8 double v;
 9 struct node
10 {
11     int to;
12     double r;
13     double c;
14     node(int tt = 0,double rr=0,double cc=0) :to(tt),r(rr),c(cc)
15     {
16     }
17 };
18 vector<node>mp[maxn];
19 double dis[maxn];
20 bool vis[maxn];
21 int cnt[maxn];
22 
23 bool SPFA(int root)
24 {
25     memset(vis, 0, sizeof(vis));
26     memset(cnt, 0, sizeof(cnt));
27     memset(dis, 0, sizeof(dis));
28     dis[root] = v, cnt[root] = 1, vis[root] = true;
29     queue<int>q;
30     q.push(root);
31     while (!q.empty())
32     {
33         int u = q.front();
34         q.pop();
35         vis[u] = false;
36         int sz = mp[u].size();
37         for (int i = 0; i < sz; i++)
38         {
39             int v = mp[u][i].to;
40             double r = mp[u][i].r;
41             double c = mp[u][i].c;
42             if (dis[v]<(dis[u]-c)*r)
43             {
44                 dis[v] = (dis[u] - c)*r;
45                 if (!vis[v])
46                 {
47                     q.push(v);
48                     vis[v] = true;
49                     cnt[v]++;
50                     if (cnt[v] > n)return true;
51                 }
52             }
53         }
54     }
55     return false;
56 }
57 void Run()
58 {
59     for (int i = 0; i <= n; i++) mp[i].clear();
60     for (int i = 0; i < m; i++)
61     {
62         int u, v;
63         double ruv, cuv, rvu, cvu;
64         scanf("%d%d%lf%lf%lf%lf", &u, &v, &ruv,&cuv,&rvu,&cvu);
65         mp[u].push_back(node(v, ruv,cuv));
66         mp[v].push_back(node(u, rvu,cvu));
67     }
68     if (SPFA(s)) printf("YES\n");
69     else printf("NO\n");
70 }
71 int main()
72 {
73     while (~scanf("%d%d%d%lf", &n, &m,&s,&v))
74     {
75         Run();
76     }
77     return 0;
78 }
View Code

6、POJ 3259 Wormholes

  题意:给出一些无向边,从一点走到另一点需要花费t时间;还有一些黑洞,能使人从一点到另一点并且返回到t时间前。问能否遇到以前的自己。

  思路:SPFA判负环。

技术分享
 1 #include<iostream>
 2 #include<vector>
 3 #include<queue>
 4 using namespace std;
 5 const int maxn = 600;
 6 const int INF = 0x7fffffff;
 7 int n, m, w;
 8 double v;
 9 struct node
10 {
11     int to;
12     int len;
13     node(int tt = 0,int ll=0) :to(tt),len(ll)
14     {
15     }
16 };
17 vector<node>mp[maxn];
18 double dis[maxn];
19 bool vis[maxn];
20 int cnt[maxn];
21 
22 bool SPFA(int root)
23 {
24     memset(vis, 0, sizeof(vis));
25     memset(cnt, 0, sizeof(cnt));
26     for (int i = 0; i <= n; i++) dis[i] = INF;
27     dis[root] = 0, cnt[root] = 1, vis[root] = true;
28     queue<int>q;
29     q.push(root);
30     while (!q.empty())
31     {
32         int u = q.front();
33         q.pop();
34         vis[u] = false;
35         int sz = mp[u].size();
36         for (int i = 0; i < sz; i++)
37         {
38             int v = mp[u][i].to;
39             int len = mp[u][i].len;
40             if (dis[u]+len<dis[v])
41             {
42                 dis[v] = dis[u] + len;
43                 if (!vis[v])
44                 {
45                     q.push(v);
46                     vis[v] = true;
47                     cnt[v]++;
48                     if (cnt[v] > n)return true;
49                 }
50             }
51         }
52     }
53     return false;
54 }
55 void Run()
56 {
57     for (int i = 0; i <= n; i++) mp[i].clear();
58     for (int i = 0; i < m; i++)
59     {
60         int u, v, l;
61         scanf("%d%d%d", &u, &v, &l);
62         mp[u].push_back(node(v,l));
63         mp[v].push_back(node(u,l));
64     }
65     for (int j = 0; j < w; j++)
66     {
67         int u, v, l;
68         scanf("%d%d%d", &u, &v, &l);
69         l = -l;
70         mp[u].push_back(node(v, l));
71     }
72     if (SPFA(1)) printf("YES\n");
73     else printf("NO\n");
74 }
75 int main()
76 {
77     int C;
78     scanf("%d", &C);
79     while (C--)
80     {
81         scanf("%d%d%d", &n, &m, &w);
82         Run();
83     }
84     return 0;
85 }
View Code

7、poj1502 - MPI Maelstrom

  题意:求从节点1到其他节点的最短路的最大值。

  思路:SPFA。

技术分享
 1 #include<iostream>
 2 #include<queue>
 3 #include<vector>
 4 #include<cstdlib>
 5 #include<algorithm>
 6 using namespace std;
 7 int n;
 8 const int maxn = 110;
 9 const int INF = 0x7fffffff;
10 struct node
11 {
12     int to;
13     int len;
14     node(int tt = 0,int ll=0):to(tt),len(ll){ }
15 };
16 vector<node>mp[maxn];
17 bool vis[maxn];
18 int cnt[maxn];
19 int pre[maxn];
20 int dis[maxn];
21 bool SPFA(int root)
22 {
23     memset(vis, 0, sizeof(vis));
24     memset(cnt, 0, sizeof(cnt));
25     for (int i = 0; i <= n; i++) dis[i] = INF, pre[i] = root;
26     dis[root] = 0, vis[root] = true, cnt[root]++;
27     queue<int>q;
28     q.push(root);
29     while (!q.empty())
30     {
31         int u = q.front();
32         q.pop();
33         vis[u] = false;
34         int sz = mp[u].size();
35         for (int i = 0; i < sz; i++)
36         {
37             int v = mp[u][i].to;
38             int len = mp[u][i].len;
39             if (dis[u] + len < dis[v])
40             {
41                 dis[v] = dis[u] + len;
42                 if (!vis[v])
43                 {
44                     vis[v] = true;
45                     q.push(v);
46                     cnt[v]++;
47                     if (cnt[v] > n)return false;
48                 }
49             }
50         }
51     }
52     return true;
53 }
54 void Run()
55 {
56     char s[25];
57     for (int i = 0; i <= n; i++) mp[i].clear();
58     for (int i = 2; i <= n; i++)
59     {
60         for (int j = 1; j < i; j++)
61         {
62             scanf("%s", s);
63             if (s[0] != x)
64             {
65                 int v = atoi(s);
66                 mp[i].push_back(node(j, v));
67                 mp[j].push_back(node(i, v));
68             }
69         }
70     }
71     SPFA(1);
72     int ans = 0;
73     for (int i = 1; i <= n; i++)
74     {
75         ans = max(ans, dis[i]);
76     }
77     printf("%d\n", ans);
78 }
79 int main()
80 {
81     while (~scanf("%d", &n))
82     {
83         Run();
84     }
85     return 0;
86 }
View Code

8、POJ 3660 Cow Contest

  题意:对于N头牛,给出一些两两比赛的结果,问最多有几头牛的名次可以确定。

  思路:Floyd拓展,根据传递性,判断两两之间的胜负。

技术分享
 1 #include<iostream>
 2 #include<memory.h>
 3 using namespace std;
 4 int n, m;
 5 const int maxn = 110;
 6 int dis[maxn][maxn];
 7 void Run()
 8 {
 9     memset(dis, 0, sizeof(dis));
10     for (int i = 0; i < m; i++)
11     {
12         int winner, failer;
13         scanf("%d%d", &winner, &failer);
14         dis[winner][failer] = 1;
15         dis[failer][winner] = -1;
16     }
17     //类Floyd
18     for (int k = 1; k <= n; k++)
19     {
20         for (int i = 1; i <= n; i++)
21         {
22             for (int j = 1; j <= n; j++)
23             {
24                 if (dis[i][k] == dis[k][j] && (dis[i][k] == 1 || dis[i][k] == -1))
25                 {//闭包传递性
26                     dis[i][j] = dis[i][k];
27                 }
28             }
29         }
30     }
31     int ans = 0;
32     for (int i = 1; i <= n; i++)
33     {
34         int ct = 0;
35         for (int j = 1; j <= n; j++)
36         {
37             if (dis[i][j] != 0) ct++;
38         }
39         if (ct == n - 1) ans++;
40     }
41     printf("%d\n", ans);
42 }
43 int main()
44 {
45     while (~scanf("%d%d", &n, &m))
46     {
47         Run();
48     }
49     return 0;
50 }
View Code

9、HDU 1217 Arbitrage

  题意:给出一些货币之间的汇率,问能否进行套汇?即通过不断兑换货币使得最后自己钱比初始多。

  思路:SPFA判正环

技术分享
 1 #include<iostream>
 2 #include<map>
 3 #include<string>
 4 #include<vector>
 5 #include<queue>
 6 using namespace std;
 7 int n,m;
 8 const int maxn = 35;
 9 map<string, int>M;
10 struct node
11 {
12     int to;
13     double r;
14     node(int tt=0,double rr=0):to(tt),r(rr){ }
15 };
16 vector<node>mp[maxn];
17 bool vis[maxn];
18 int cnt[maxn];
19 double dis[maxn];
20 bool SPFA()
21 {
22     memset(vis, 0, sizeof(vis));
23     memset(cnt, 0, sizeof(cnt));
24     memset(dis, 0, sizeof(dis));
25     dis[1] = 1, vis[1] = true, cnt[1]++;
26     queue<int>q;
27     q.push(1);
28     while (!q.empty())
29     {
30         int u = q.front();
31         q.pop();
32         vis[u] = false;
33         int sz = mp[u].size();
34         for (int i = 0; i < sz; i++)
35         {
36             int v = mp[u][i].to;
37             double rt = mp[u][i].r;
38             double tv = dis[u] * rt;
39             if (tv> dis[v])
40             {
41                 dis[v] = dis[u] * rt;
42                 if (!vis[v])
43                 {
44                     q.push(v);
45                     vis[v] = true;
46                     cnt[v]++;
47                     if (cnt[v] > n)return true;
48                 }
49             }
50         }
51     }
52     return false;
53 }
54 int main()
55 {
56     int Case = 1;
57     while (~scanf("%d", &n))
58     {
59         if (n == 0) break;
60         for (int i = 0; i <= n; i++) mp[i].clear();
61         string s;
62         M.clear();
63         cin.get();
64         for (int i = 0; i < n; i++)
65         {
66             getline(cin, s);
67             M[s] = i + 1;
68         }
69         scanf("%d", &m);
70         string a, b;
71         double rt;
72         for (int i = 0; i < m; i++)
73         {
74             cin >> a >> rt >> b;
75             int ida = M[a];
76             int idb = M[b];
77             mp[ida].push_back(node(idb, rt));
78         }
79         if (SPFA()) printf("Case %d: Yes\n", Case);
80         else printf("Case %d: No\n", Case);
81         Case++;
82     }
83     return 0;
84 }
View Code

10、POJ 1511 HDU1535 Invitation Cards

  题意:先从1到其他各点,在从其他各点回到1.求总共最小花费。

  思路:通过逆向建边即只需通过两次SPFA即可求出答案。

技术分享
 1 #include<iostream>
 2 #include<vector>
 3 #include<queue>
 4 using namespace std;
 5 int p, q;
 6 const int maxp = 1000010;
 7 const int INF = 0x7fffffff;
 8 bool vis[maxp];
 9 int cnt[maxp];
10 int pre[maxp];
11 int dis[maxp];
12 long long sum;
13 struct node
14 {
15     int to;
16     int fee;
17     node(int tt=0,int ff=0):to(tt),fee(ff){ }
18 };
19 vector<node>mp[maxp];
20 struct points
21 {
22     int from;
23     int to;
24     int v;
25 }pp[maxp];
26 bool SPFA(int root)
27 {
28     for (int i = 0; i <= p; i++)
29     {
30         dis[i] = INF;
31         pre[i] = root;
32         cnt[i] = 0;
33         vis[i] = false;
34     }
35     queue<int>q;
36     q.push(root);
37     dis[root]=0,cnt[root] = 1, vis[root] = true;
38     while (!q.empty())
39     {
40         int u = q.front();
41         q.pop();
42         vis[u] = false;
43         int sz = mp[u].size();
44         for (int i = 0; i < sz; i++)
45         {
46             int v = mp[u][i].to;
47             int ff = mp[u][i].fee;
48             if (dis[u] + ff < dis[v])
49             {
50                 dis[v] = dis[u] + ff;
51                 if (!vis[v])
52                 {
53                     vis[v] = true;
54                     cnt[v]++;
55                     q.push(v);
56                     if (cnt[v] > p)return false;
57                 }
58             }
59         }
60     }
61     return true;
62 }
63 void RSet()
64 {
65     for (int i = 0; i <= p; i++) mp[i].clear();
66     for (int i = 0; i < q; i++)
67     {
68         mp[pp[i].to].push_back(node(pp[i].from, pp[i].v));
69     }
70 }
71 int main()
72 {
73     int t;
74     scanf("%d", &t);
75     while (t--)
76     {
77         scanf("%d%d", &p, &q);
78         for (int i = 0; i <= p; i++) mp[i].clear();
79         for (int i = 0; i < q; i++)
80         {
81             int u, v, f;
82             scanf("%d%d%d", &u, &v, &f);
83             mp[u].push_back(node(v, f));
84             pp[i].from = u, pp[i].to = v, pp[i].v = f;
85         }
86         sum = 0;
87         SPFA(1);
88         for (int i = 2; i <= p; i++) sum += dis[i];
89         RSet();
90         SPFA(1);
91         for (int i = 2; i <= p; i++) sum += dis[i];
92         printf("%lld\n", sum);
93     }
94 
95 
96     return 0;
97 }
View Code

11、POJ 3159 Candies(差分约束+栈SPFA)

  题意:给出若干对(A,B,C),B的糖果不能比A多C,求第N个人最多比第1个人多多少?

  思路:B-A<=C,差分约束,建立从A到B的有向边,权值为C。通过模拟栈来代替队列,否则TLE,同时用边表代替vector邻接表。

技术分享
 1 #include<iostream>
 2 using namespace std;
 3 int n, m;
 4 const int maxn = 30100;
 5 const int INF = 0x7ffffff;
 6 struct eg
 7 {
 8     int to,next;
 9     int v;
10 }Edge[150100];
11 int head[maxn];
12 
13 bool vis[maxn];
14 int cnt[maxn];
15 int dis[maxn];
16 
17 int stk[maxn], top;//模拟栈
18 bool SPFA(int root)
19 {
20     for (int i = 0; i <= n; i++) dis[i] = INF;
21     memset(vis, 0, sizeof(vis));
22     memset(cnt, 0, sizeof(cnt));
23     dis[root] = 0, vis[root] = true, cnt[root]++;
24     top = 0;
25     stk[top++] = root;
26     while (top)
27     {
28         int u = stk[--top];
29         vis[u] = false;
30         for (int i = head[u]; i!=-1; i=Edge[i].next)
31         {
32             int v = Edge[i].to;
33             int vv = Edge[i].v;
34             if (dis[u] + vv < dis[v])
35             {
36                 dis[v] = dis[u] + vv;
37                 if (!vis[v])
38                 {
39                     vis[v] = true;
40                     cnt[v]++;
41                     stk[top++] = v;
42                     if (cnt[v] > n)return false;
43                 }
44             }
45         }
46     }
47     return true;
48 }
49 int main()
50 {
51     while (~scanf("%d%d", &n, &m))
52     {
53         memset(head, -1, sizeof(head));
54         for (int i = 0; i < m; i++)
55         {
56             int u, v, f;
57             scanf("%d%d%d", &u, &v, &f);
58             //v不能比u超过f个糖果:v-u<=f
59             Edge[i].to =v, Edge[i].v = f,Edge[i].next=head[u];
60             head[u] = i;
61         }
62         SPFA(1);//求v(n)-v(1)<=?
63         printf("%d\n", dis[n]);
64     }
65     return 0;
66 }
View Code

12、POJ 2502 Subway

  题意:给出家和学校的位置,再给出若干条地铁线路所经站点的位置,给出步行和地铁的速度,求从家到学校的最短时间。

  思路:预处理图:只有同一线路的相邻地铁站点才能通过地铁,否则步行。SPFA。

技术分享
 1 #include<iostream>
 2 #include<queue>
 3 #include<cmath>
 4 using namespace std;
 5 const int maxn = 210;
 6 const double INF = 1e9;
 7 int n;
 8 struct node
 9 {
10     int x;
11     int y;
12     node(int xx=0,int yy=0):x(xx),y(yy){ }
13 };
14 node points[maxn];
15 double dis[maxn];
16 double D[maxn][maxn];
17 bool vis[maxn];
18 int cnt[maxn];
19 int id;
20 bool SPFA(int root)
21 {
22     for (int i = 0; i <= id; i++) dis[i] = INF;
23     memset(vis, 0, sizeof(vis));
24     queue<int>q;
25     q.push(root);
26     dis[root] = 0, vis[root] = true, cnt[root] = 1;
27     while (!q.empty())
28     {
29         int u = q.front();
30         q.pop();
31         vis[u] = false;
32         for (int i = 1; i <= id; i++)
33         {
34             if (dis[u] + D[u][i] < dis[i])
35             {
36                 dis[i] = dis[u] + D[u][i];
37                 if (!vis[i])
38                 {
39                     vis[i] = true;
40                     cnt[i]++;
41                     q.push(i);
42                     if (cnt[i] > id)return false;
43                 }
44             }
45         }
46     }
47     return true;
48 }
49 int main()
50 {
51     //freopen("in.txt", "r", stdin);
52     double v1 = 40000.0 / 60.0;
53     double v2 = 10000.0 / 60.0;
54     while (~scanf("%d%d%d%d", &points[1].x, &points[1].y, &points[2].x, &points[2].y))
55     {
56         memset(D, 0, sizeof(D));
57         id = 2;
58         bool isfirst = true;
59         int tx, ty;
60         while (~scanf("%d%d", &tx, &ty))
61         {
62             if (tx == -1 && ty == -1)
63             {
64                 isfirst = true;
65                 continue;
66             }
67             if (isfirst)
68             {
69                 isfirst = false;
70                 id++;
71                 points[id].x = tx, points[id].y = ty;
72             }
73             else
74             {
75                 id++;
76                 points[id].x = tx, points[id].y = ty;
77                 D[id][id - 1]=D[id - 1][id] = sqrt(1.0*(points[id].x - points[id - 1].x)*(points[id].x - points[id - 1].x) + (points[id].y - points[id - 1].y)*(points[id].y - points[id - 1].y))/v1;
78             }
79         }
80         for (int i = 1; i <= id; i++)
81         {
82             for (int j = i+1; j <= id; j++)
83             {
84                 if (D[i][j] == 0)
85                 {
86                     D[i][j]=D[j][i]= sqrt(1.0*(points[i].x - points[j].x)*(points[i].x - points[j].x) + (points[i].y - points[j].y)*(points[i].y - points[j].y)) / v2;
87                 }
88             }
89         }//以上预处理各点间的距离,只有相邻车站才能用地铁,否则都为步行
90         SPFA(1);
91         printf("%.0lf\n", dis[2]);
92     }
93     return 0;
94 }
View Code

13、POJ 1062 昂贵的聘礼

  题意:探险家需要给酋长若干钱币,如果他能够找来一些其他物品能够得到优惠,同时如果探险家和某个人交易后,阶级超过限制的人不会再和他交易。问最少的花费。

  思路:把探险家和所有的人看成一个点,原价看成是探险家到其他人的路径的权值,优惠为其他人之间路径的权值。最后求从探险家到酋长的最短路。不过需要根据阶级限制枚举能够交易的人,最后取min。

技术分享
 1 #include<iostream>
 2 #include<vector>
 3 #include<queue>
 4 using namespace std;
 5 int M, N;
 6 const int maxn = 110;
 7 const int INF = 0x7fffffff;
 8 struct node
 9 {
10     int to;
11     int fee;
12     node(int tt=0,int ff=0):to(tt),fee(ff){ }
13 };
14 int lvl[maxn];
15 vector<node>mp[maxn];
16 int dis[maxn];
17 int cnt[maxn];
18 bool vis[maxn];
19 bool SPFA(int root, int limitl, int limitr)
20 {
21     memset(vis, 0, sizeof(vis));
22     memset(cnt, 0, sizeof(cnt));
23     for (int i = 0; i <= N; i++) dis[i] = INF;
24     dis[root] = 0, vis[root] = true, cnt[root]++;
25     queue<int>q;
26     q.push(root);
27     while (!q.empty())
28     {
29         int u = q.front();
30         q.pop();
31         int sz = mp[u].size();
32         for (int i = 0; i < sz; i++)
33         {
34             int v = mp[u][i].to;
35             int fee = mp[u][i].fee;
36             if (lvl[v]<limitl || lvl[v]>limitr)continue;
37             if (dis[u] + fee < dis[v])
38             {
39                 dis[v] = dis[u] + fee;
40                 if (!vis[v])
41                 {
42                     vis[v] = true;
43                     cnt[v]++;
44                     q.push(v);
45                     if (cnt[v] > N+1)return false;
46                 }
47             }
48         }
49         vis[u] = false;
50     }
51     return true;
52 }
53 int main()
54 {
55     while (~scanf("%d%d", &M, &N))
56     {
57         for (int i = 0; i <= N; i++) mp[i].clear();
58         for (int i = 1; i <= N; i++)
59         {
60             int cost, level, x;
61             scanf("%d%d%d", &cost, &level, &x);
62             mp[0].push_back(node(i, cost));
63             lvl[i] = level;
64             for (int j = 0; j < x; j++)
65             {
66                 int u, cost2;
67                 scanf("%d%d", &u, &cost2);
68                 mp[u].push_back(node(i, cost2));
69             }
70         }
71         int ans = INF;
72         for (int limit = lvl[1] - M; limit <= lvl[1]; limit++)
73         {
74             SPFA(0,limit,limit+M);
75             ans = min(ans, dis[1]);
76         }
77         printf("%d\n", ans);
78     }
79     return 0;
80 }
View Code

13、POJ 1847 Tram

  题意:给出若干结点和哪些结点连通,每个结点有个初始朝向,如果要换轨,则变换次数+1.求最少的变换次数。

  思路:SPFA,若两节点之间无需换轨,权值为0,否则权值置为1.SPFA

技术分享
 1 #include<iostream>
 2 #include<vector>
 3 #include<queue>
 4 using namespace std;
 5 int N, A, B;
 6 const int maxn = 110;
 7 const int INF = 0x7fffffff;
 8 struct node
 9 {
10     int to;
11     int fee;
12     node(int tt=0,int ff=0):to(tt),fee(ff){ }
13 };
14 vector<node>mp[maxn];
15 int dis[maxn];
16 bool vis[maxn];
17 int cnt[maxn];
18 int pre[maxn];
19 bool SPFA(int root)
20 {
21     memset(vis, 0, sizeof(vis));
22     memset(cnt, 0, sizeof(cnt));
23     for (int i = 0; i <= N; i++) dis[i] = INF, pre[i] = root;
24     dis[root] = 0, vis[root] = true, cnt[root]++;
25     queue<int>q;
26     q.push(root);
27     while (!q.empty())
28     {
29         int u = q.front();
30         q.pop();
31         vis[u] = false;
32         int sz = mp[u].size();
33         for (int i = 0; i < sz; i++)
34         {
35             int v = mp[u][i].to;
36             int f = mp[u][i].fee;
37             if (dis[u] + f < dis[v])
38             {
39                 dis[v] = dis[u] + f;
40                 if (!vis[v])
41                 {
42                     vis[v] = true;
43                     cnt[v]++;
44                     q.push(v);
45                     if (cnt[v] > N)return false;
46                 }
47             }
48         }
49     }
50     return true;
51 }
52 int main()
53 {
54     while (~scanf("%d%d%d", &N, &A, &B))
55     {
56         for (int i = 0; i <= N; i++) mp[i].clear();
57         for (int i = 1; i <= N; i++)
58         {
59             int k;
60             scanf("%d", &k);
61             for (int j = 0; j < k; j++)
62             {
63                 int to;
64                 scanf("%d", &to);
65                 if (j == 0)mp[i].push_back(node(to, 0));
66                 else mp[i].push_back(node(to, 1));
67             }
68         }
69         SPFA(A);
70         if(dis[B]!=INF)printf("%d\n", dis[B]);
71         else printf("-1\n");
72     }
73     return 0;
74 }
View Code

14、lightOJ 1074 Extended Traffic

  题意:每个路口有个拥挤度,从一个路口到另一个路口的时间为目标路口的拥挤度减去起点处的拥挤度的3次方。求从1到给定路口的最小时间。

  思路:SPFA。注意负环的存在,如果存在负环,则标记负环中的点和从负环能到达的点。

技术分享
 1 #include<iostream>
 2 #include<vector>
 3 #include<queue>
 4 #include<memory.h>
 5 #include<cstdio>
 6 using namespace std;
 7 const int maxn = 210;
 8 const int INF = 0x7fffffff;
 9 int n, m, q;
10 int busy[maxn];
11 struct node
12 {
13     int to;
14     int dd;
15     node(int tt=0,int d=0):to(tt),dd(d){ }
16 };
17 vector<node>mp[maxn];
18 bool vis[maxn];
19 bool isfu[maxn];
20 int dis[maxn];
21 int cnt[maxn];
22 bool SPFA(int root)
23 {
24     memset(vis, 0, sizeof(vis));
25     memset(cnt, 0, sizeof(cnt));
26     memset(isfu, 0, sizeof(isfu));
27     for (int i = 0; i <= n; i++) dis[i] = INF;
28     dis[root] = 0, cnt[root]++, vis[root] = true;
29     queue<int>q;
30     q.push(root);
31     while (!q.empty())
32     {
33         int u = q.front();
34         q.pop();
35         vis[u] = false;
36         int sz = mp[u].size();
37         for (int i = 0; i < sz; i++)
38         {
39             int v = mp[u][i].to;
40             int ff = mp[u][i].dd;
41             if (isfu[v])continue;
42             if (dis[u] + ff < dis[v])
43             {
44                 dis[v] = dis[u] + ff;
45                 if (!vis[v])
46                 {
47                     q.push(v);
48                     cnt[v]++;
49                     vis[v] = true;
50                     if (cnt[v] > n)isfu[v] = true;
51                 }
52             }
53         }
54 
55     }
56     return true;
57 }
58 int main()
59 {
60     int t;
61     int Case = 1;
62     scanf("%d", &t);
63     while (t--)
64     {
65         scanf("%d", &n);
66         for (int i = 0; i <= n; i++) mp[i].clear();
67         for (int i = 1; i <= n; i++) scanf("%d", &busy[i]);
68         scanf("%d", &m);
69         for (int i = 0; i < m; i++)
70         {
71             int u, v;
72             scanf("%d%d", &u, &v);
73             int len = (busy[v] - busy[u])*(busy[v] - busy[u])*(busy[v] - busy[u]);
74             mp[u].push_back(node(v, len));
75         }
76         SPFA(1);
77         scanf("%d", &q);
78         printf("Case %d:\n", Case++);
79         for (int i = 0; i < q; i++)
80         {
81             int des;
82             scanf("%d", &des);
83             if (isfu[des] || dis[des] == INF || dis[des] < 3)printf("?\n");
84             else printf("%d\n",dis[des]);
85         }
86     }
87     return 0;
88 }
View Code

15、hdu 4725 The Shortest Path in Nya Graph

  题意:每个点都有各自所在的层次,相邻层之间穿越要c时间,还有一些桥,相互之间到达要花费时间。求从1到N的最小时间。

  思路:SPFA,关键在于构建边。

技术分享
 1 #include<iostream>
 2 #include<vector>
 3 #include<queue>
 4 using namespace std;
 5 int n, m, c;
 6 const int maxn = 100010;
 7 const int INF = 0x7fffffff;
 8 int layer[maxn];
 9 struct node
10 {
11     int to;
12     int val;
13     node(int tt=0,int vv=0):to(tt),val(vv){ }
14 };
15 vector<node>mp[maxn*2];
16 
17 bool vis[maxn*2];
18 int dis[maxn*2];
19 int cnt[maxn*2];
20 int cntl[maxn];
21 bool SPFA(int root)
22 {
23     memset(vis, 0, sizeof(vis));
24     memset(cnt, 0, sizeof(cnt));
25     for (int i = 0; i <= n*2; i++) dis[i] = INF;
26     dis[root] = 0, cnt[root]++, vis[root] = true;
27     queue<int>q;
28     q.push(root);
29     while (!q.empty())
30     {
31         int u = q.front();
32         q.pop();
33         vis[u] = false;
34         int sz = mp[u].size();
35         for (int i = 0; i < sz; i++)
36         {
37             int v = mp[u][i].to;
38             int f = mp[u][i].val;
39             if (dis[u] + f < dis[v])
40             {
41                 dis[v] = dis[u] + f;
42                 if (!vis[v])
43                 {
44                     vis[v] = true;
45                     q.push(v);
46                     cnt[v]++;
47                     if (cnt[v] > n)return false;
48                 }
49             }
50         }
51     }
52     return true;
53 }
54 int main()
55 {
56     int t;
57     scanf("%d", &t);
58     int Case = 1;
59     while (t--)
60     {
61         memset(cntl, 0, sizeof(cntl));
62         scanf("%d%d%d", &n, &m, &c);
63         for (int i = 0; i <= n*2; i++) mp[i].clear();
64         for (int i = 1; i <= n; i++)
65         {
66             scanf("%d", &layer[i]);
67             cntl[layer[i]]++;
68         }
69         for (int i = 1; i < n; i++)
70         {//相邻层建边
71             if (cntl[i] && cnt[i + 1])
72             {
73                 mp[n + i].push_back(node(n + i + 1, c));
74                 mp[n + 1 + i].push_back(node(n + i, c));
75             }
76         }
77         for (int i = 1; i <= n; i++)
78         {
79             mp[n + layer[i]].push_back(node(i, 0));//从点所在层到该点建边(不能反向,否则同一层的点最后距离都为0)
80             if (layer[i] > 1) mp[i].push_back(node(n + layer[i] - 1, c));//从该点到其下一层建边
81             if (layer[i] < n) mp[i].push_back(node(n + layer[i] + 1, c));//从该点到其上一层建边
82         }
83         for (int i = 0; i < m; i++)
84         {
85             int u,v, w;
86             scanf("%d%d%d", &u, &v, &w);
87             mp[u].push_back(node(v, w));
88             mp[v].push_back(node(u, w));
89         }
90         SPFA(1);
91         if (dis[n] == INF) printf("Case #%d: -1\n",Case++);
92         else printf("Case #%d: %d\n", Case++, dis[n]);
93     }
94     return 0;
95 }
View Code

 

 


以上是关于最短路专题(不定期更新)的主要内容,如果未能解决你的问题,请参考以下文章

kuangbin专题最短路练习

排列专题(不定期更新)

[专题-图论]最短路

最短路径算法专题2----Dijkstra

线段树专题(不定期更新)

最短路径算法专题1----弗洛伊德