《挑战程序设计竞赛》课后练习题解集——2.5 它们其实都是“图”

2.5 它们其实都是“图”

最短路

AOJ 0189  求图上一点,到所有其他点的距离之和最小

Floyd算法

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3
 4 const int inf = 1e8;
 5 int d[11][11];
 6
 7 int main() {
 8     int n;
 9     while (cin >> n) {
10         if (n == 0) break;
11
12         for (int i = 0; i <= 9; i++)
13             for (int j = 0; j <= 9; j++) d[i][j] = inf;
14         for (int i = 0; i <= 9; i++) d[i][i] = 0;
15
16         int x, y, z, v = 0;
17         while (n--) {
18             cin >> x >> y >> z;
19             v = max(max(x, y), v);
20             d[x][y] = z;
21             d[y][x] = z;
22         }
23
24         for (int k = 0; k <= v; k++) {
25             for (int i = 0; i <= v; i++) {
26                 for (int j = 0; j <= v; j++)
27                     d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
28             }
29         }
30
31         int sum = inf, number;
32         for (int i = 0; i <= v; i++) {
33             int t = 0;
34             for (int j = 0; j <= v; j++) t += d[i][j];
35             if (sum > t) {
36                 sum = t;
37                 number = i;
38             }
39         }
40
41         cout << number << " " << sum << "\n";
42     }
43 }

POJ 2139  同上一题,结果乘100除以n-1

 1 #include <cstdio>
 2 #include <iostream>
 3 using namespace std;
 4
 5 int d[305][305], x[305];
 6
 7 int main() {
 8     int n, m, num;
 9     for (int i = 1; i <= 300; i++) fill(d[i], d[i] + 305, 0x7f7f7f);
10     for (int i = 1; i <= 300; i++) d[i][i] = 0;
11     cin >> n >> m;
12     for (int i = 0; i < m; i++) {
13         cin >> num;
14         for (int j = 0; j < num; j++) {
15             cin >> x[j];
16             for (int k = 0; k < j; k++) {
17                 d[x[k]][x[j]] = 1;
18                 d[x[j]][x[k]] = 1;
19             }
20         }
21     }
22     for (int i = 1; i <= n; i++) {
23         for (int j = 1; j <= n; j++) {
24             for (int k = 1; k <= n; k++)
25                 d[j][k] = min(d[j][k], d[j][i] + d[i][k]);
26         }
27     }
28     int sum = (int)1e9;
29     for (int i = 1; i <= n; i++) {
30         int t = 0;
31         for (int j = 1; j <= n; j++) t += d[i][j];
32         sum = min(sum, t);
33     }
34     cout << sum * 100 / (n - 1);
35 }

POJ 3259  判断是否有负环

BF算法

 1 #include <cstring>
 2 #include <iostream>
 3 using namespace std;
 4
 5 int d[505];
 6
 7 struct edge {
 8     int from, to, cost;
 9 };
10
11 edge es[5205];
12
13 int main() {
14     int t, n, m, w, x, y, z;
15     cin >> t;
16     while (t--) {
17         cin >> n >> m >> w;
18         for (int i = 0; i < m; i++) {
19             cin >> x >> y >> z;
20             es[2 * i] = {x, y, z};
21             es[2 * i + 1] = {y, x, z};
22         }
23         for (int i = 2 * m; i < 2 * m + w; i++) {
24             cin >> x >> y >> z;
25             es[i] = {x, y, -z};
26         }
27         memset(d, 0, sizeof(d));
28         int flag = 0;
29         for (int i = 1; i <= n; i++) {
30             for (int j = 0; j < 2 * m + w; j++) {
31                 edge e = es[j];
32                 if (d[e.to] > d[e.from] + e.cost) {
33                     d[e.to] = d[e.from] + e.cost;
34                     if (i == n) {
35                         cout << "YES\n";
36                         flag = 1;
37                         break;
38                     }
39                 }
40             }
41         }
42         if (flag == 0) cout << "NO\n";
43     }
44 }

POJ 3268  求所有点到某一点来回的最短路中的最大值

dij求该点到所有点的最短路,反过来时把所有边反向即可

 1 #include <cstring>
 2 #include <iostream>
 3 using namespace std;
 4
 5 int d[505];
 6
 7 struct edge {
 8     int from, to, cost;
 9 };
10
11 edge es[5205];
12
13 int main() {
14     int t, n, m, w, x, y, z;
15     cin >> t;
16     while (t--) {
17         cin >> n >> m >> w;
18         for (int i = 0; i < m; i++) {
19             cin >> x >> y >> z;
20             es[2 * i] = {x, y, z};
21             es[2 * i + 1] = {y, x, z};
22         }
23         for (int i = 2 * m; i < 2 * m + w; i++) {
24             cin >> x >> y >> z;
25             es[i] = {x, y, -z};
26         }
27         memset(d, 0, sizeof(d));
28         int flag = 0;
29         for (int i = 1; i <= n; i++) {
30             for (int j = 0; j < 2 * m + w; j++) {
31                 edge e = es[j];
32                 if (d[e.to] > d[e.from] + e.cost) {
33                     d[e.to] = d[e.from] + e.cost;
34                     if (i == n) {
35                         cout << "YES\n";
36                         flag = 1;
37                         break;
38                     }
39                 }
40             }
41         }
42         if (flag == 0) cout << "NO\n";
43     }
44 }

AOJ 2249  给出一个连通图,每条边具有距离和修建的成本。要删去一些边,使得从起点1出发到其他的点的最短路径不变 而省下的修建成本尽可能多

可以把修建的成本当做第二维费用 跑dij

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define ll long long
 4 #define inc(i, l, r) for (int i = l; i <= r; i++)
 5 #define pii pair<int, int>
 6 #define fi first
 7 #define se second
 8 #define pb push_back
 9
10 const int maxv = 1e4 + 5;
11 const int inf = 0x3f3f3f3f;
12 int V, d[maxv], c[maxv], m, res;
13 struct edge {
14     int to, dis, cost;
15     bool operator>(const edge& o) const {
16         if (dis == o.dis) return cost > o.cost;
17         return dis > o.dis;
18     }
19 };
20 vector<edge> g[maxv];
21
22 void dij(int s) {
23     priority_queue<edge, vector<edge>, greater<edge> > que;
24     inc(i, 1, V) d[i] = c[i] = inf;
25     d[s] = c[s] = 0;
26     que.push({s, 0, 0});
27     while (!que.empty()) {
28         edge p = que.top();
29         que.pop();
30         int v = p.to;
31         if (d[v] < p.dis || (d[v] == p.dis && c[v] < p.cost)) continue;
32         for (int i = 0; i < g[v].size(); i++) {
33             edge e = g[v][i];
34             if (d[e.to] > d[v] + e.dis ||
35                 (d[e.to] == d[v] + e.dis && c[e.to] > e.cost)) {
36                 d[e.to] = d[v] + e.dis;
37                 c[e.to] = e.cost;
38                 que.push({e.to, d[e.to], c[e.to]});
39             }
40         }
41     }
42 }
43
44 int u, v, x, y;
45
46 int main() {
47     while (scanf("%d %d", &V, &m) != EOF && V) {
48         inc(i, 1, V) g[i].clear();
49         inc(i, 1, m) {
50             scanf("%d %d %d %d", &u, &v, &x, &y);
51             g[u].pb({v, x, y});
52             g[v].pb({u, x, y});
53         }
54         dij(1);
55         res = 0;
56         inc(i, 1, V) res += c[i];
57         printf("%d\n", res);
58     }
59 }

AOJ 2200  给出一个图,边有陆路和水路。有个快递员要经过一系列点,他有辆船,走水路时必须用船,走陆路时船得留在出发时的起点,要用船时得回去取。求最短距离

好题目。Floyd分别预处理陆路和水路,dp[i][j]表示当前走到第i个城镇,船停在第j号城镇的最段距离。转移时考虑去取船,走水路,下船走陆路这一过程。特别,可以不取船走陆路到下一个地方

(最开始我dp想当然觉得船都是停在目标路径上的节点,其实不然)

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define ll long long
 4 #define inc(i, l, r) for (int i = l; i <= r; i++)
 5
 6 const int inf = 2e8;
 7
 8 int n, m, r;
 9 int d1[205][205], d2[205][205];
10 int path[1005], dp[1005][205];
11
12 void init(int p[][205]) {
13     inc(i, 1, n) inc(j, 1, n) p[i][j] = inf;
14     inc(i, 1, n) p[i][i] = 0;
15 }
16
17 void floyd(int p[][205]) {
18     inc(k, 1, n) inc(i, 1, n) inc(j, 1, n) p[i][j] =
19         min(p[i][j], p[i][k] + p[k][j]);
20 }
21
22 int x, y, z;
23 char c;
24
25 int main() {
26     while (scanf("%d %d", &n, &m) != EOF && n) {
27         init(d1), init(d2);
28         inc(i, 1, m) {
29             scanf("%d %d %d %c", &x, &y, &z, &c);
30             if (c == ‘L‘)
31                 d1[x][y] = d1[y][x] = min(d1[x][y], z);
32             else
33                 d2[x][y] = d2[y][x] = min(d2[x][y], z);
34         }
35         floyd(d1), floyd(d2);
36
37         scanf("%d", &r);
38         inc(i, 1, r) scanf("%d", &path[i]);
39
40         inc(i, 1, n) dp[1][i] = inf;
41         dp[1][path[1]] = 0;
42
43         inc(i, 2, r) {
44             inc(j, 1, n) {
45                 dp[i][j] = inf;
46                 inc(k, 1, n) {
47                     dp[i][j] = min(dp[i][j], dp[i - 1][k] + d1[path[i - 1]][k] +
48                                                  d2[k][j] + d1[j][path[i]]);
49                     if (k == j)
50                         dp[i][j] = min(dp[i][j],
51                                        dp[i - 1][k] + d1[path[i - 1]][path[i]]);
52                 }
53             }
54         }
55
56         int res = inf;
57         inc(i, 1, n) res = min(res, dp[r][i]);
58         printf("%d\n", res);
59     }
60 }

最小生成树

POJ 1258  给出一个图的邻接矩阵,求最小生成树

 1 #include <algorithm>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <iostream>
 5 using namespace std;
 6
 7 int par[105], rankk[105];
 8 struct edge {
 9     int u, v, cost;
10 } es[10005];
11
12 bool cmp(const edge &x, const edge &y) { return x.cost < y.cost; }
13
14 void init(int x) {
15     for (int i = 1; i <= x; i++) {
16         par[i] = i;
17         rankk[i] = 0;
18     }
19 }
20
21 int find(int x) {
22     if (par[x] == x) return x;
23     return par[x] = find(par[x]);
24 }
25
26 void unite(int x, int y) {
27     x = find(x);
28     y = find(y);
29     if (x == y) return;
30     if (rankk[x] < rankk[y])
31         par[x] = y;
32     else {
33         par[y] = x;
34         if (rankk[x] == rankk[y]) rankk[x]++;
35     }
36 }
37
38 bool same(int x, int y) { return find(x) == find(y); }
39
40 int main() {
41     int n, x, l;
42     while (~scanf("%d", &n)) {
43         init(n);
44         l = 0;
45         memset(es, 0, sizeof(es));
46         for (int i = 1; i <= n; i++) {
47             for (int j = 1; j <= n; j++) {
48                 scanf("%d", &x);
49                 if (i == j) continue;
50                 es[l++] = {i, j, x};
51             }
52         }
53         sort(es, es + l, cmp);
54         int res = 0;
55         for (int i = 0; i < l; i++) {
56             edge e = es[i];
57             if (!same(e.u, e.v)) {
58                 unite(e.u, e.v);
59                 res += e.cost;
60             }
61         }
62         printf("%d\n", res);
63     }
64 }

POJ 2377  最大生成树

 1 #include <algorithm>
 2 #include <cstdio>
 3 #include <iostream>
 4 using namespace std;
 5
 6 int par[1001], rankk[1001];
 7
 8 struct edge {
 9     int u, v, cost;
10 } es[20001];
11
12 void init(int x) {
13     for (int i = 1; i <= x; i++) {
14         par[i] = i;
15         rankk[i] = 0;
16     }
17 }
18
19 int find(int x) {
20     if (par[x] == x) return x;
21     return par[x] = find(par[x]);
22 }
23
24 void unite(int x, int y) {
25     x = find(x);
26     y = find(y);
27     if (x == y) return;
28     if (rankk[y] > rankk[x]) {
29         par[x] = y;
30     } else {
31         par[y] = x;
32         if (rankk[x] == rankk[y]) rankk[x]++;
33     }
34 }
35
36 bool same(int x, int y) { return find(x) == find(y); }
37
38 bool cmp(edge x, edge y) { return x.cost > y.cost; }
39
40 int main() {
41     int n, m, x, y, z, res = 0, sum = 0;
42     cin >> n >> m;
43     init(n);
44     for (int i = 0; i < m; i++) {
45         scanf("%d%d%d", &x, &y, &z);
46         es[i] = {x, y, z};
47     }
48     sort(es, es + m, cmp);
49     for (int i = 0; i < m; i++) {
50         edge e = es[i];
51         if (!same(e.u, e.v)) {
52             unite(e.u, e.v);
53             sum += e.cost;
54             res++;
55         }
56     }
57     if (res == n - 1)
58         printf("%d", sum);
59     else
60         printf("-1");
61 }

AOJ 2224  给出一个图,要求删去一些边,使得删去后 被这些边划分的所有区域是互相联通的。要使删去的边边长和最小
这题难度在于条件转换。题意等价于图删去一些边后没有环。考虑删边后的图 的边长要尽可能的大,即 是由 若干最大生成树组成的森林

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define ll long long
 4 #define inc(i, l, r) for (int i = l; i <= r; i++)
 5 #define pii pair<double, int>
 6 #define fi first
 7 #define se second
 8 #define pb push_back
 9
10 const double inf = 1e9;
11 const int maxv = 1e5 + 5;
12
13 struct edge {
14     double cost;
15     int u, v;
16     bool operator<(const edge &o) const { return cost > o.cost; }
17 };
18
19 double x[maxv], y[maxv], tot;
20 int n, m, a, b;
21
22 int par[maxv];
23 void init() { inc(i, 1, n) par[i] = i; }
24 int find(int x) {
25     if (x == par[x]) return x;
26     return par[x] = find(par[x]);
27 }
28 void unite(int x, int y) {
29     x = find(x), y = find(y);
30     if (x != y) par[x] = y;
31 }
32 bool same(int x, int y) { return find(x) == find(y); }
33
34 int main() {
35     scanf("%d %d", &n, &m);
36     vector<edge> g(m);
37     inc(i, 1, n) scanf("%lf %lf", &x[i], &y[i]);
38     inc(i, 0, m - 1) {
39         scanf("%d %d", &a, &b);
40         double dis =
41             sqrt((x[a] - x[b]) * (x[a] - x[b]) + (y[a] - y[b]) * (y[a] - y[b]));
42         g[i] = {dis, a, b};
43         tot += dis;
44     }
45     sort(g.begin(), g.end());
46     init();
47     inc(i, 0, m - 1) {
48         int u = g[i].u, v = g[i].v;
49         if (!same(u, v)) {
50             tot -= g[i].cost;
51             unite(u, v);
52         }
53     }
54     printf("%.3f", tot);
55 }

POJ 2395  给定一个图,求它的联通子图(含所有点)最大边的最小值

即最小生成树的最大边

 1 #include <algorithm>
 2 #include <cstdio>
 3 #include <iostream>
 4 #include <vector>
 5 using namespace std;
 6 #define inc(i, l, r) for (int i = l; i <= r; i++)
 7
 8 const int maxv = 2e3 + 5;
 9
10 int par[maxv], n, m, u, v, x;
11
12 struct edge {
13     int u, v, cost;
14     bool operator<(const edge& o) const { return cost < o.cost; }
15 } g[10005];
16
17 void init() { inc(i, 1, n) par[i] = i; }
18 int find(int x) {
19     if (x == par[x]) return x;
20     return par[x] = find(par[x]);
21 }
22 void unite(int x, int y) {
23     x = find(x), y = find(y);
24     if (x != y) par[x] = y;
25 }
26 bool same(int x, int y) { return find(x) == find(y); }
27
28 int main() {
29     scanf("%d %d", &n, &m);
30     init();
31     inc(i, 0, m - 1) {
32         scanf("%d %d %d", &u, &v, &x);
33         g[i] = edge{u, v, x};
34     }
35     sort(g, g + m);
36     int res = 0;
37     inc(i, 0, m - 1) {
38         int u = g[i].u, v = g[i].v;
39         if (!same(u, v)) {
40             unite(u, v);
41             res = max(res, g[i].cost);
42         }
43     }
44     printf("%d\n", res);
45 }

END

原文地址:https://www.cnblogs.com/hs-zlq/p/12233550.html

时间: 2024-10-10 02:04:40

《挑战程序设计竞赛》课后练习题解集——2.5 它们其实都是“图”的相关文章

《挑战程序设计竞赛》课后练习题解集——3.4 熟练掌握动态规划

<挑战程序设计竞赛>课后练习题解集——3.4 熟练掌握动态规划 状态压缩DP POJ 2441  有N头牛,M个槽,N,M≤20,每头牛只在指定的pi个槽里进食,不与其他牛共享槽.问有多少种分配方案. dp[i][S],当前第i头牛要进食,槽的使用状态为S 1 #include <cstdio> 2 #include <cstring> 3 #include <vector> 4 using namespace std; 5 6 int n, m; 7 in

[转] AOJ 0525 Osenbei《挑战程序设计竞赛(第2版)》练习题答案

来自 码农场 ? AOJ 0525 Osenbei<挑战程序设计竞赛(第2版)>练习题答案 只把代码复制过来,原博的其他分析请看链接. 1 #include <iostream> 2 #include <bitset> 3 #include <algorithm> 4 5 using namespace std; 6 7 bitset<10000> cookie[10]; 8 9 ///////////////////////////SubMai

POJ 3420 Quad Tiling 题解 《挑战程序设计竞赛》

POJ 3420 Quad Tiling贴瓷砖:4*N的地板上用2*1的瓷砖铺满,求所有方案数对M求余.3.4熟练掌握动态规划矩阵的幂久违地上了节课,太无聊,只好刷一题.假设S[n]表示填满n时的方案数,有S[0]=1.定义矩阵M[p][q] := 边缘p和边缘q可以拼合时取1,否则取0所谓的可以拼合表示,两个边缘拼起来后长度为1(为2就拼接不起来了),且内部缝隙可以用2*1的瓷砖填满.那么M就有一些简单的性质了,比如M的第一行应该是:0 0 0 0 0 0... 继续阅读:码农场 » POJ

POJ 3411 Paid Roads 题解 《挑战程序设计竞赛》

POJ 3411 Paid Roads开路:N个城市间有m条单向路,分别从a到b,可以在c处交P路费,也可以直接交R路费.那么问题来了,你的挖掘机怎么开最省钱?3.4熟练掌握动态规划状态压缩DP乍一看可以Dijkstra,实际上的确可以Dijkstra.不过多了一个预交费的c,所以在遍历的时候多了一维状态,这个维度储存当前走过的城市集合.在Dijkstra的时候,如果走过了c那么就有两个选择,选其中最省的即可:否则没得选.#include <iostream> #include&nb.

字符串HASH模板 取自挑战程序设计竞赛(第2版)

/*===================================================* 从b串中寻找和a串长度相同的子串,返回开始位置 不保证绝对正确,发生冲突概率为O(sqrt(n)), n为哈希函数的最大值 \*===================================================*/ #define ull unsigned long long const ull B = 1e8+7; /*according to the book*/

POJ 2836 Rectangular Covering 题解 《挑战程序设计竞赛》

POJ 2836 Rectangular Covering铺地板:坐标平面上有n各点,用任意大小(非零)的地板砖覆盖它们,求最省的地板砖总面积.3.4熟练掌握动态规划状态压缩DP先预处理数据,将n个点两两组合形成n * (n-1) / 2个矩形,计算每个矩形的面积和内部点个数.接着利用预处理数据来枚举,定义dp[S] := 矩形集为S时的最省面积先假设平面上没有矩形,那么dp[0]=0,接着一个一个地往平面上加矩形,递推关系是:dp[新矩形集合] = min(dp[新矩形集合], dp[旧矩形集

poj2431 Expedition (优先队列) 挑战程序设计竞赛

题目链接:http://poj.org/problem?id=2431 Expedition Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 9148   Accepted: 2673 Description A group of cows grabbed a truck and ventured on an expedition deep into the jungle. Being rather poor driver

Aizu 2249Road Construction 单源最短路变形《挑战程序设计竞赛》模板题

King Mercer is the king of ACM kingdom. There are one capital and some cities in his kingdom. Amazingly, there are no roads in the kingdom now. Recently, he planned to construct roads between the capital and the cities, but it turned out that the con

38天刷完挑战程序设计竞赛&amp;数论概论计划

现在是2017年12月6日22:03:36,在做数论概论的chapter6线性方程与最大公因数的习题时,粗略地翻了一下挑战程序设计竞赛,感觉相见恨晚:遂决定38天刷完挑战程序设计竞赛和数论概论. 时间:2017年12月7日00:00:00 -- 2018年1月15日00:00:00 目前进度:数论概论完成前6章,挑战程序设计竞赛完成0 目标:刷完数论概论44章,理解所有定理和证明,刷完全部练习 刷完挑战程序设计竞赛4章共406页,理解所有知识点和证明,刷完全部例题和习题(此目标可以调整,比如跳过