[关闭]
@Dmaxiya 2020-08-25T00:40:29.000000Z 字数 17011 阅读 1102

图论练习题解

Hello_World


2月19日 树/图上 bfs/dfs 练习题解

A. Coloring a Tree

题意

给一棵 个节点的无色的树上色,对于每一次上色,选择一个点后,可以将这个点所对应的子树都图上同一种颜色,现在给定树的结构,问最少需要上几次颜色,能够使得每个节点的颜色和题目表示的颜色相同。

数据范围

题解

从根节点(下标为 的节点)开始往下 ,只要父节点和子节点的颜色不同,就将答案加一,最后输出答案。

过题代码

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstdlib>
  4. #include <cmath>
  5. #include <climits>
  6. #include <cstring>
  7. #include <string>
  8. #include <vector>
  9. #include <list>
  10. #include <queue>
  11. #include <stack>
  12. #include <map>
  13. #include <set>
  14. #include <bitset>
  15. #include <algorithm>
  16. #include <functional>
  17. #include <iomanip>
  18. using namespace std;
  19. #define LL long long
  20. const int maxn = 10000 + 100;
  21. int n, tmp;
  22. int color[maxn];
  23. vector<int> G[maxn];
  24. int dfs(int x) {
  25. int ret = 0;
  26. int len = G[x].size();
  27. for(int i = 0; i < len; ++i) {
  28. int pos = G[x][i];
  29. ret += dfs(pos);
  30. ret += (color[pos] != color[x]);
  31. }
  32. return ret;
  33. }
  34. int main() {
  35. #ifdef LOCAL
  36. freopen("test.txt", "r", stdin);
  37. // freopen("out.txt", "w", stdout);
  38. #endif // LOCAL
  39. ios::sync_with_stdio(false);
  40. while(scanf("%d", &n) != EOF) {
  41. for(int i = 1; i <= n; ++i) {
  42. G[i].clear();
  43. }
  44. for(int i = 2; i <= n; ++i) {
  45. scanf("%d", &tmp);
  46. G[tmp].push_back(i);
  47. }
  48. for(int i = 1; i <= n; ++i) {
  49. scanf("%d", &color[i]);
  50. }
  51. printf("%d\n", dfs(1) + 1);
  52. }
  53. return 0;
  54. }

B. 确定比赛名次

题解

从所有的胜利者向失败者连一条有向边,然后进行拓扑排序(最开始将所有入度为零的点加入队列,再进行宽搜,对于每个弹出队列的点,将它的后继节点的入度减一,如果某个后继节点的入度为零,则进入队列),由于题目要求输出字典序最小的,所以将队列改成优先队列即可。

过题代码

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstdlib>
  4. #include <cmath>
  5. #include <climits>
  6. #include <cstring>
  7. #include <string>
  8. #include <vector>
  9. #include <list>
  10. #include <queue>
  11. #include <stack>
  12. #include <map>
  13. #include <set>
  14. #include <bitset>
  15. #include <algorithm>
  16. #include <functional>
  17. #include <iomanip>
  18. using namespace std;
  19. #define LL long long
  20. const int maxn = 600;
  21. int n, m, u, v;
  22. int cnt, ans[maxn];
  23. vector<int> G[maxn];
  24. int deg[maxn];
  25. priority_queue<int, vector<int>, greater<int> > que;
  26. void topsort() {
  27. cnt = 0;
  28. for(int i = 1; i <= n; ++i) {
  29. if(deg[i] == 0) {
  30. que.push(i);
  31. }
  32. }
  33. while(!que.empty()) {
  34. int tmp = que.top();
  35. que.pop();
  36. ans[cnt++] = tmp;
  37. int len = G[tmp].size();
  38. for(int i = 0; i < len; ++i) {
  39. int pos = G[tmp][i];
  40. --deg[pos];
  41. if(deg[pos] == 0) {
  42. que.push(pos);
  43. }
  44. }
  45. }
  46. }
  47. int main() {
  48. #ifdef LOCAL
  49. freopen("test.txt", "r", stdin);
  50. // freopen("out.txt", "w", stdout);
  51. #endif // LOCAL
  52. ios::sync_with_stdio(false);
  53. while(scanf("%d%d", &n, &m) != EOF) {
  54. for(int i = 1; i <= n; ++i) {
  55. G[i].clear();
  56. }
  57. for(int i = 0; i < m; ++i) {
  58. scanf("%d%d", &u, &v);
  59. G[u].push_back(v);
  60. ++deg[v];
  61. }
  62. topsort();
  63. for(int i = 0; i < cnt; ++i) {
  64. if(i != 0) {
  65. printf(" ");
  66. }
  67. printf("%d", ans[i]);
  68. }
  69. printf("\n");
  70. }
  71. return 0;
  72. }

C. Labyrinth

题意

故事太长略去,就是在一个 的迷宫内找到任意两点最短距离的最大值。

数据范围

题解

这题是裸的求树的直径(从任意一点开始,找到离这个点最远的点 ,再从 点找到另一个离 点最远的点 之间的距离就是树的直径)的题目,但是树上是没有环的,所以求路径长度就是最短路径,这题相当于是有环的图,所以就按照题目要求求出任意两点最短路径,作为“树”上距离,然后求直径就行了。

过题代码

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstdlib>
  4. #include <cmath>
  5. #include <climits>
  6. #include <cstring>
  7. #include <string>
  8. #include <vector>
  9. #include <list>
  10. #include <queue>
  11. #include <stack>
  12. #include <map>
  13. #include <set>
  14. #include <bitset>
  15. #include <algorithm>
  16. #include <functional>
  17. #include <iomanip>
  18. using namespace std;
  19. #define LL long long
  20. const int maxn = 1000 + 100;
  21. struct Node {
  22. int x, y;
  23. Node() {}
  24. Node(int xx, int yy) {
  25. x = xx;
  26. y = yy;
  27. }
  28. };
  29. int T, n, m, x, y;
  30. char str[maxn][maxn];
  31. queue<Node> que;
  32. int step[maxn][maxn];
  33. const int dir[4][2] = {{-1, 0}, {0, -1}, {1, 0}, {0, 1}};
  34. bool in(int x, int y) {
  35. return x >= 0 && x < n && y >= 0 && y < m;
  36. }
  37. void bfs() {
  38. memset(step, -1, sizeof(step));
  39. step[x][y] = 0;
  40. que.push(Node(x, y));
  41. while(!que.empty()) {
  42. Node tmp = que.front();
  43. que.pop();
  44. for(int i = 0; i < 4; ++i) {
  45. int xx = tmp.x + dir[i][0];
  46. int yy = tmp.y + dir[i][1];
  47. if(in(xx, yy) && step[xx][yy] == -1 && str[xx][yy] == '.') {
  48. step[xx][yy] = step[tmp.x][tmp.y] + 1;
  49. que.push(Node(xx, yy));
  50. if(step[xx][yy] > step[x][y]) {
  51. x = xx;
  52. y = yy;
  53. }
  54. }
  55. }
  56. }
  57. }
  58. int main() {
  59. #ifdef LOCAL
  60. freopen("test.txt", "r", stdin);
  61. // freopen("out.txt", "w", stdout);
  62. #endif // LOCAL
  63. ios::sync_with_stdio(false);
  64. scanf("%d", &T);
  65. while(T--) {
  66. scanf("%d%d", &m, &n);
  67. for(int i = 0; i < n; ++i) {
  68. scanf("%s", str[i]);
  69. for(int j = 0; j < m; ++j) {
  70. if(str[i][j] == '.') {
  71. x = i;
  72. y = j;
  73. }
  74. }
  75. }
  76. bfs();
  77. bfs();
  78. printf("Maximum rope length is %d.\n", step[x][y]);
  79. }
  80. return 0;
  81. }

2月20日 欧拉路练习

A. 欧拉路·一

题解

题解题目已经给出。
这题数据出水了,没有用并查集判连通块也被你们过了,但是后面如果碰到判断欧拉路的问题,一定要记得先判连通块。

过题代码

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstdlib>
  4. #include <cmath>
  5. #include <climits>
  6. #include <cstring>
  7. #include <string>
  8. #include <vector>
  9. #include <list>
  10. #include <queue>
  11. #include <stack>
  12. #include <map>
  13. #include <set>
  14. #include <bitset>
  15. #include <algorithm>
  16. #include <functional>
  17. #include <iomanip>
  18. using namespace std;
  19. #define LL long long
  20. const int maxn = 10000 + 100;
  21. int n, m, u, v;
  22. bool flag;
  23. int fa[maxn], deg[maxn];
  24. void Init() {
  25. flag = true;
  26. memset(deg, 0, sizeof(deg));
  27. for(int i = 1; i <= n; ++i) {
  28. fa[i] = i;
  29. }
  30. }
  31. int Find(int x) {
  32. return (x == fa[x]? x: fa[x] = Find(fa[x]));
  33. }
  34. void unit(int x, int y) {
  35. int xx = Find(x);
  36. int yy = Find(y);
  37. fa[xx] = yy;
  38. }
  39. int main() {
  40. #ifdef LOCAL
  41. freopen("test.txt", "r", stdin);
  42. // freopen("out.txt", "w", stdout);
  43. #endif // LOCAL
  44. ios::sync_with_stdio(false);
  45. while(scanf("%d%d", &n, &m) != EOF) {
  46. Init();
  47. for(int i = 0; i < m; ++i) {
  48. scanf("%d%d", &u, &v);
  49. unit(u, v);
  50. ++deg[u];
  51. ++deg[v];
  52. }
  53. for(int i = 2; i <= n; ++i) {
  54. if(Find(i) != Find(1)) {
  55. flag = false;
  56. break;
  57. }
  58. }
  59. if(!flag) {
  60. printf("Part\n");
  61. continue;
  62. }
  63. int cnt = 0;
  64. for(int i = 1; i <= n; ++i) {
  65. cnt += (deg[i] % 2);
  66. }
  67. if(cnt == 0 || cnt == 2) {
  68. printf("Full\n");
  69. } else {
  70. printf("Part\n");
  71. }
  72. }
  73. return 0;
  74. }

B. 欧拉路·二

题解

题解题目已经给出,主要代码也在第一页给出。

过题代码

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstdlib>
  4. #include <cmath>
  5. #include <climits>
  6. #include <cstring>
  7. #include <string>
  8. #include <vector>
  9. #include <list>
  10. #include <queue>
  11. #include <stack>
  12. #include <map>
  13. #include <set>
  14. #include <bitset>
  15. #include <algorithm>
  16. #include <functional>
  17. #include <iomanip>
  18. using namespace std;
  19. #define LL long long
  20. const int maxn = 5000 + 100;
  21. struct Node {
  22. int pos;
  23. int Index;
  24. Node() {}
  25. Node(int p, int I) {
  26. pos = p;
  27. Index = I;
  28. }
  29. };
  30. struct Edge {
  31. int u, v;
  32. };
  33. int n, m, cnt, u, v;
  34. int deg[maxn];
  35. bool vis[maxn];
  36. Edge ans[maxn];
  37. vector<Node> G[maxn];
  38. void dfs(int x) {
  39. int len = G[x].size();
  40. for(int i = 0; i < len; ++i) {
  41. int pos = G[x][i].pos;
  42. int Index = G[x][i].Index;
  43. if(!vis[Index]) {
  44. vis[Index] = true;
  45. dfs(pos);
  46. ans[cnt].u = x;
  47. ans[cnt++].v = pos;
  48. }
  49. }
  50. }
  51. int main() {
  52. #ifdef LOCAL
  53. freopen("test.txt", "r", stdin);
  54. // freopen("out.txt", "w", stdout);
  55. #endif // LOCAL
  56. ios::sync_with_stdio(false);
  57. while(scanf("%d%d", &n, &m) != EOF) {
  58. cnt = 0;
  59. memset(vis, 0, sizeof(vis));
  60. for(int i = 1; i <= n; ++i) {
  61. G[i].clear();
  62. deg[i] = 0;
  63. }
  64. for(int i = 0; i < m; ++i) {
  65. scanf("%d%d", &u, &v);
  66. G[u].push_back(Node(v, i));
  67. G[v].push_back(Node(u, i));
  68. ++deg[u];
  69. ++deg[v];
  70. }
  71. for(int i = 1; i <= n; ++i) {
  72. if(deg[i] % 2 == 1) {
  73. u = i;
  74. break;
  75. }
  76. }
  77. dfs(u);
  78. for(int i = cnt - 1; i >= 0; --i) {
  79. printf("%d ", ans[i].u);
  80. }
  81. printf("%d\n", ans[0].v);
  82. }
  83. return 0;
  84. }

C. 欧拉路·三

题解

题解题目已经给出。这题涉及到位运算可能不太熟悉,其实位运算的 ~ 和逻辑运算符的 非常类似,只是将数字转化为二进制数后进行按位“与或非”,这里以 为例:


还有两个是左移和右移运算符,对于正数,左移运算符将 的所有二进制位向高位移动,溢出部分直接舍去,低位补 ,右移运算符将 的所有二进制位向低位移动,溢出部分直接社区,高位补 ,负数只是将补 改为补 ,这里以 为例:

还有一个不太好理解的可能就是为什么题目用那样的构图方法,我看起来感觉题目已经说得很清楚了,如果有什么问题的话可以私戳我,说明具体是哪个地方没看懂。
这题的过题代码就加一些注释吧。

过题代码

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstdlib>
  4. #include <cmath>
  5. #include <climits>
  6. #include <cstring>
  7. #include <string>
  8. #include <vector>
  9. #include <list>
  10. #include <queue>
  11. #include <stack>
  12. #include <map>
  13. #include <set>
  14. #include <bitset>
  15. #include <algorithm>
  16. #include <functional>
  17. #include <iomanip>
  18. using namespace std;
  19. #define LL long long
  20. const int maxn = (1 << 15); // 实际上只需要 1 << 14,可以想一想为什么
  21. struct Node {
  22. int pos; // 表示节点所代表的数字,就是图示中的两位二进制数,范围:[0,(1<<14)-1]
  23. int weight; // 表示边权,就是图示中的三位二进制数,范围:[0,(1<<15)-1]
  24. Node() {}
  25. Node(int p, int w) {
  26. pos = p;
  27. weight = w;
  28. }
  29. };
  30. int n, cnt;
  31. int ans[maxn];
  32. vector<Node> G[maxn];
  33. bool vis[maxn];
  34. // 寻找欧拉路经
  35. void dfs(int x) {
  36. int len = G[x].size();
  37. for(int i = 0; i < len; ++i) {
  38. int pos = G[x][i].pos;
  39. int weight = G[x][i].weight;
  40. if(!vis[weight]) {
  41. vis[weight] = true;
  42. dfs(pos);
  43. ans[cnt++] = weight;
  44. }
  45. }
  46. }
  47. int main() {
  48. #ifdef LOCAL
  49. freopen("test.txt", "r", stdin);
  50. // freopen("out.txt", "w", stdout);
  51. #endif // LOCAL
  52. ios::sync_with_stdio(false);
  53. while(scanf("%d", &n) != EOF) {
  54. cnt = 0;
  55. memset(vis, 0, sizeof(vis));
  56. int up = (1 << (n - 1)); // 节点范围为 [0,(1<<(n-1))-1]
  57. for(int i = 0; i < up; ++i) {
  58. G[i].clear();
  59. }
  60. for(int i = 0; i < up; ++i) {
  61. G[i].push_back(Node(((i << 1) & (~up)), (i << 1)));
  62. G[i].push_back(Node((((i << 1) & (~up)) | 1), (i << 1 | 1)));
  63. // 这里取 ~up 只是一巧合,实际上应该是 ~(1<<(n-1))(恰好等于 up),与上这个值的作用是去掉 i<<1 的最高位
  64. }
  65. dfs(0);
  66. for(int i = cnt - 1; i >= 0; --i) {
  67. printf("%d", (ans[i] & 1));
  68. // 输出欧拉路径,其实这里于上的值可以为 [1,1<<1,1<<2,...,1<<(n-1)],因为是环上的 01 是循环的,所以取边权的任意位都是对的
  69. }
  70. printf("\n");
  71. }
  72. return 0;
  73. }

2月21日 dij & floyd 练习

A. 畅通工程续

题解

单源最短路裸题。

过题代码

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstdlib>
  4. #include <cmath>
  5. #include <climits>
  6. #include <cstring>
  7. #include <string>
  8. #include <vector>
  9. #include <list>
  10. #include <queue>
  11. #include <stack>
  12. #include <map>
  13. #include <set>
  14. #include <bitset>
  15. #include <algorithm>
  16. #include <functional>
  17. #include <iomanip>
  18. using namespace std;
  19. #define LL long long
  20. const int maxn = 300;
  21. struct Node {
  22. int pos;
  23. int dis;
  24. Node() {}
  25. Node(int p, int d) {
  26. pos = p;
  27. dis = d;
  28. }
  29. };
  30. bool operator<(const Node &a, const Node &b) {
  31. return a.dis > b.dis;
  32. }
  33. int INF;
  34. int n, m, u, v, d, s, t;
  35. int dis[maxn];
  36. vector<Node> G[maxn];
  37. priority_queue<Node> que;
  38. void dij(int s) {
  39. memset(dis, 0x3f, sizeof(dis));
  40. dis[s] = 0;
  41. que.push(Node(s, 0));
  42. while(!que.empty()) {
  43. Node tmp = que.top();
  44. que.pop();
  45. int len = G[tmp.pos].size();
  46. for(int i = 0; i < len; ++i) {
  47. int pos = G[tmp.pos][i].pos;
  48. d = G[tmp.pos][i].dis;
  49. if(dis[pos] > dis[tmp.pos] + d) {
  50. dis[pos] = dis[tmp.pos] + d;
  51. que.push(Node(pos, dis[pos]));
  52. }
  53. }
  54. }
  55. }
  56. int main() {
  57. #ifdef LOCAL
  58. freopen("test.txt", "r", stdin);
  59. // freopen("out.txt", "w", stdout);
  60. #endif // LOCAL
  61. ios::sync_with_stdio(false);
  62. memset(&INF, 0x3f, sizeof(int));
  63. while(scanf("%d%d", &n, &m) != EOF) {
  64. for(int i = 0; i < n; ++i) {
  65. G[i].clear();
  66. }
  67. for(int i = 0; i < m; ++i) {
  68. scanf("%d%d%d", &u, &v, &d);
  69. G[u].push_back(Node(v, d));
  70. G[v].push_back(Node(u, d));
  71. }
  72. scanf("%d%d", &s, &t);
  73. dij(s);
  74. if(dis[t] == INF) {
  75. printf("-1\n");
  76. } else {
  77. printf("%d\n", dis[t]);
  78. }
  79. }
  80. return 0;
  81. }

B. Invitation Cards

题意

故事太长。问题就是在一个 个节点, 条边的有向图上,求从起点到所有车站的花费 ,以及从所有车站回到起点的花费总和。

数据范围

题解

找起点到其他所有点的最短路,就直接从起点开始跑一遍最短路,找所有其他点到起点的花费总和,可以将所有边反向,然后从起点开始跑一遍最短路。注意虽然每一条最短路最大值为 ,但是所有最短路的总和就要爆 了,所以计算最短路的过程中可以用 ,而求和的时候必须用 储存。
一不小心找了一道卡常题,失误失误,不过看你们被 的地方好像不是很难处理,虽然数据量比较大,但是不卡 ,用 又不取消同步被卡,就是自己的问题了。这题我被卡的地方是开了两个邻接链表数组,只开一个的话就能过,比较玄学就是了。

过题代码

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstdlib>
  4. #include <cmath>
  5. #include <climits>
  6. #include <cstring>
  7. #include <string>
  8. #include <vector>
  9. #include <list>
  10. #include <queue>
  11. #include <stack>
  12. #include <map>
  13. #include <set>
  14. #include <bitset>
  15. #include <algorithm>
  16. #include <functional>
  17. #include <iomanip>
  18. using namespace std;
  19. #define LL long long
  20. const int maxn = 1000000 + 100;
  21. struct Node {
  22. int pos;
  23. int dis;
  24. Node() {}
  25. Node(int p, int d) {
  26. pos = p;
  27. dis = d;
  28. }
  29. };
  30. bool operator<(const Node &a, const Node &b) {
  31. return a.dis > b.dis;
  32. }
  33. int T, n, m;
  34. int u[maxn], v[maxn], d[maxn];
  35. LL ans;
  36. int dis[maxn];
  37. vector<Node> G[maxn];
  38. priority_queue<Node> que;
  39. void Clear() {
  40. for(int i = 1; i <= n; ++i) {
  41. G[i].clear();
  42. }
  43. }
  44. void dij(int s) {
  45. memset(dis, 0x3f, sizeof(int) * (n + 1));
  46. dis[s] = 0;
  47. que.push(Node(s, 0));
  48. while(!que.empty()) {
  49. Node tmp = que.top();
  50. que.pop();
  51. int len = G[tmp.pos].size();
  52. for(int i = 0; i < len; ++i) {
  53. int pos = G[tmp.pos][i].pos;
  54. int d = G[tmp.pos][i].dis;
  55. if(dis[pos] > tmp.dis + d) {
  56. dis[pos] = tmp.dis + d;
  57. que.push(Node(pos, dis[pos]));
  58. }
  59. }
  60. }
  61. for(int i = 1; i <= n; ++i) {
  62. ans += dis[i];
  63. }
  64. }
  65. int main() {
  66. #ifdef LOCAL
  67. freopen("test.txt", "r", stdin);
  68. // freopen("out.txt", "w", stdout);
  69. #endif // LOCAL
  70. ios::sync_with_stdio(false);
  71. scanf("%d", &T);
  72. while(T--) {
  73. ans = 0;
  74. scanf("%d%d", &n, &m);
  75. Clear();
  76. for(int i = 0; i < m; ++i) {
  77. scanf("%d%d%d", &u[i], &v[i], &d[i]);
  78. G[u[i]].push_back(Node(v[i], d[i]));
  79. }
  80. dij(1);
  81. Clear();
  82. for(int i = 0; i < m; ++i) {
  83. G[v[i]].push_back(Node(u[i], d[i]));
  84. }
  85. dij(1);
  86. printf("%lld\n", ans);
  87. }
  88. return 0;
  89. }

C. Choose the best route

题意

在一个 个节点, 条边的有向图中,从给定的 个点中,找到这些点到终点 最短路径的最小值。

数据范围

题解

同样地,每条边都反向构图,然后从 点开始跑一遍最短路。

过题代码

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstdlib>
  4. #include <cmath>
  5. #include <climits>
  6. #include <cstring>
  7. #include <string>
  8. #include <vector>
  9. #include <list>
  10. #include <queue>
  11. #include <stack>
  12. #include <map>
  13. #include <set>
  14. #include <bitset>
  15. #include <algorithm>
  16. #include <functional>
  17. #include <iomanip>
  18. using namespace std;
  19. #define LL long long
  20. const int maxn = 1000 + 100;
  21. struct Node {
  22. int pos;
  23. int dis;
  24. Node() {}
  25. Node(int p, int d) {
  26. pos = p;
  27. dis = d;
  28. }
  29. };
  30. bool operator<(const Node &a, const Node &b) {
  31. return a.dis > b.dis;
  32. }
  33. int INF;
  34. int n, m, s, u, v, d, w, ans;
  35. int dis[maxn];
  36. vector<Node> G[maxn];
  37. priority_queue<Node> que;
  38. void dij() {
  39. dis[s] = 0;
  40. que.push(Node(s, 0));
  41. while(!que.empty()) {
  42. Node tmp = que.top();
  43. que.pop();
  44. int len = G[tmp.pos].size();
  45. for(int i = 0; i < len; ++i) {
  46. int pos = G[tmp.pos][i].pos;
  47. d = G[tmp.pos][i].dis;
  48. if(dis[pos] > tmp.dis + d) {
  49. dis[pos] = tmp.dis + d;
  50. que.push(Node(pos, dis[pos]));
  51. }
  52. }
  53. }
  54. }
  55. int main() {
  56. #ifdef LOCAL
  57. freopen("test.txt", "r", stdin);
  58. // freopen("out.txt", "w", stdout);
  59. #endif // LOCAL
  60. ios::sync_with_stdio(false);
  61. memset(&INF, 0x3f, sizeof(int));
  62. while(scanf("%d%d%d", &n, &m, &s) != EOF) {
  63. for(int i = 1; i <= n; ++i) {
  64. G[i].clear();
  65. dis[i] = INF;
  66. }
  67. for(int i = 0; i < m; ++i) {
  68. scanf("%d%d%d", &u, &v, &d);
  69. G[v].push_back(Node(u, d));
  70. }
  71. dij();
  72. ans = INF;
  73. scanf("%d", &w);
  74. for(int i = 0; i < w; ++i) {
  75. scanf("%d", &u);
  76. ans = min(ans, dis[u]);
  77. }
  78. if(ans == INF) {
  79. printf("-1\n");
  80. } else {
  81. printf("%d\n", ans);
  82. }
  83. }
  84. return 0;
  85. }

D. find the safest road

题解

裸题,但是不是多源最短路,而是最长路,安全系数的计算方式为乘法。

过题代码

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstdlib>
  4. #include <cmath>
  5. #include <climits>
  6. #include <cstring>
  7. #include <string>
  8. #include <vector>
  9. #include <list>
  10. #include <queue>
  11. #include <stack>
  12. #include <map>
  13. #include <set>
  14. #include <bitset>
  15. #include <algorithm>
  16. #include <functional>
  17. #include <iomanip>
  18. using namespace std;
  19. #define LL long long
  20. const double eps = 1e-6;
  21. const int maxn = 1000 + 100;
  22. int n, q, u, v;
  23. double G[maxn][maxn];
  24. bool zero(const double &x) {
  25. return fabs(x) < eps;
  26. }
  27. int main() {
  28. #ifdef LOCAL
  29. freopen("test.txt", "r", stdin);
  30. // freopen("out.txt", "w", stdout);
  31. #endif // LOCAL
  32. ios::sync_with_stdio(false);
  33. while(scanf("%d", &n) != EOF) {
  34. for(int i = 1; i <= n; ++i) {
  35. for(int j = 1; j <= n; ++j) {
  36. scanf("%lf", &G[i][j]);
  37. }
  38. }
  39. for(int k = 1; k <= n; ++k) {
  40. for(int i = 1; i <= n; ++i) {
  41. for(int j = 1; j <= n; ++j) {
  42. G[i][j] = max(G[i][j], G[i][k] * G[k][j]);
  43. }
  44. }
  45. }
  46. scanf("%d", &q);
  47. for(int i = 0; i < q; ++i) {
  48. scanf("%d%d", &u, &v);
  49. if(zero(G[u][v])) {
  50. printf("What a pity!\n");
  51. } else {
  52. printf("%.3f\n", G[u][v]);
  53. }
  54. }
  55. }
  56. return 0;
  57. }

2月22日 并查集&最小生成树练习

A. D-City

题意

在一个 个节点的图上, 将按顺序破坏图上所有的 条边,问每破坏一条边,剩余的连通块有多少个。

数据范围

题解

将破坏的顺序反过来,变成加边的顺序,就可以用并查集统计连通块的个数了。

过题代码

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstdlib>
  4. #include <cmath>
  5. #include <climits>
  6. #include <cstring>
  7. #include <string>
  8. #include <vector>
  9. #include <list>
  10. #include <queue>
  11. #include <stack>
  12. #include <map>
  13. #include <set>
  14. #include <bitset>
  15. #include <algorithm>
  16. #include <functional>
  17. #include <iomanip>
  18. using namespace std;
  19. #define LL long long
  20. const int maxn = 10000 + 100;
  21. const int maxm = 100000 + 100;
  22. struct Node {
  23. int u, v;
  24. };
  25. int n, m;
  26. Node node[maxm];
  27. int fa[maxn], ans[maxm];
  28. void Init() {
  29. for(int i = 0; i < n; ++i) {
  30. fa[i] = i;
  31. }
  32. }
  33. int Find(int x) {
  34. return (x == fa[x]? x: fa[x] = Find(fa[x]));
  35. }
  36. void unit(int x, int y) {
  37. int xx = Find(x);
  38. int yy = Find(y);
  39. fa[xx] = yy;
  40. }
  41. int main() {
  42. #ifdef LOCAL
  43. freopen("test.txt", "r", stdin);
  44. // freopen("out.txt", "w", stdout);
  45. #endif // LOCAL
  46. ios::sync_with_stdio(false);
  47. while(scanf("%d%d", &n, &m) != EOF) {
  48. Init();
  49. for(int i = 1; i <= m; ++i) {
  50. scanf("%d%d", &node[i].u, &node[i].v);
  51. }
  52. int cnt = n;
  53. ans[m] = cnt;
  54. for(int i = m; i >= 1; --i) {
  55. int u = node[i].u;
  56. int v = node[i].v;
  57. if(Find(u) != Find(v)) {
  58. --cnt;
  59. unit(u, v);
  60. }
  61. ans[i - 1] = cnt;
  62. }
  63. for(int i = 1; i <= m; ++i) {
  64. printf("%d\n", ans[i]);
  65. }
  66. }
  67. return 0;
  68. }

B. 畅通工程

题解

裸的最小生成树问题,用克鲁斯卡尔就可以解决。最后注意要先判是否能够全连通。

过题代码

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstdlib>
  4. #include <cmath>
  5. #include <climits>
  6. #include <cstring>
  7. #include <string>
  8. #include <vector>
  9. #include <list>
  10. #include <queue>
  11. #include <stack>
  12. #include <map>
  13. #include <set>
  14. #include <bitset>
  15. #include <algorithm>
  16. #include <functional>
  17. #include <iomanip>
  18. using namespace std;
  19. #define LL long long
  20. const int maxn = 200;
  21. struct Node {
  22. int u, v;
  23. int dis;
  24. };
  25. bool operator<(const Node &a, const Node &b) {
  26. return a.dis < b.dis;
  27. }
  28. int n, m, ans;
  29. int fa[maxn];
  30. Node node[maxn];
  31. void Init() {
  32. ans = 0;
  33. for(int i = 1; i <= n; ++i) {
  34. fa[i] = i;
  35. }
  36. }
  37. int Find(int x) {
  38. return (x == fa[x]? x: fa[x] = Find(fa[x]));
  39. }
  40. void unit(int x, int y) {
  41. int xx = Find(x);
  42. int yy = Find(y);
  43. fa[xx] = yy;
  44. }
  45. int main() {
  46. #ifdef LOCAL
  47. freopen("test.txt", "r", stdin);
  48. // freopen("out.txt", "w", stdout);
  49. #endif // LOCAL
  50. ios::sync_with_stdio(false);
  51. while(scanf("%d%d", &m, &n), m != 0) {
  52. Init();
  53. for(int i = 0; i < m; ++i) {
  54. scanf("%d%d%d", &node[i].u, &node[i].v, &node[i].dis);
  55. }
  56. sort(node, node + m);
  57. for(int i = 0; i < m; ++i) {
  58. int u = node[i].u;
  59. int v = node[i].v;
  60. if(Find(u) != Find(v)) {
  61. unit(u, v);
  62. ans += node[i].dis;
  63. }
  64. }
  65. int f = Find(1);
  66. bool flag = true;
  67. for(int i = 1; i <= n; ++i) {
  68. if(Find(i) != f) {
  69. flag = false;
  70. break;
  71. }
  72. }
  73. if(flag) {
  74. printf("%d\n", ans);
  75. } else {
  76. printf("?\n");
  77. }
  78. }
  79. return 0;
  80. }

C. Arctic Network

题意

个卫星和 个哨站,如果某一个位于点 的哨站上有卫星,就可以与其他任何一个有卫星的哨站相互通信,如果没有,就只能和距离自己不超过 的其他哨站通信,问要使得所有哨站之间相互通信,这个 的最小值是多少。

数据范围

题解

要求最短的 ,就是在完全图上求最小生成树上距离最大的边,但是由于有卫星的哨站可以与任何其他有卫星的哨站联系,而不受距离限制,所以如果把每个有卫星的哨站分到不同的连通块里,也能使所有哨站相互通信。为使 最小,可以将生成树中最长的几条边去掉,去完边后,在不同的连通块内的任意一点放卫星。由于树上删边,删一条边多一个连通块,所以最多可以删 条边。

过题代码

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstdlib>
  4. #include <cmath>
  5. #include <climits>
  6. #include <cstring>
  7. #include <string>
  8. #include <vector>
  9. #include <list>
  10. #include <queue>
  11. #include <stack>
  12. #include <map>
  13. #include <set>
  14. #include <bitset>
  15. #include <algorithm>
  16. #include <functional>
  17. #include <iomanip>
  18. using namespace std;
  19. #define LL long long
  20. const int maxn = 600;
  21. struct Node {
  22. int u, v;
  23. int dis;
  24. };
  25. bool operator<(const Node &a, const Node &b) {
  26. return a.dis < b.dis;
  27. }
  28. struct Point {
  29. int x, y;
  30. };
  31. double ans;
  32. int T, s, p, cnt;
  33. Node node[maxn * maxn];
  34. Point point[maxn];
  35. int fa[maxn];
  36. int get_dis(int i, int j) {
  37. int dx = point[i].x - point[j].x;
  38. int dy = point[i].y - point[j].y;
  39. return dx * dx + dy * dy;
  40. }
  41. void Init() {
  42. for(int i = 0; i < p; ++i) {
  43. fa[i] = i;
  44. }
  45. }
  46. int Find(int x) {
  47. return (x == fa[x]? x: fa[x] = Find(fa[x]));
  48. }
  49. void unit(int x, int y) {
  50. int xx = Find(x);
  51. int yy = Find(y);
  52. fa[xx] = yy;
  53. }
  54. int main() {
  55. #ifdef LOCAL
  56. freopen("test.txt", "r", stdin);
  57. // freopen("out.txt", "w", stdout);
  58. #endif // LOCAL
  59. ios::sync_with_stdio(false);
  60. scanf("%d", &T);
  61. while(T--) {
  62. cnt = 0;
  63. scanf("%d%d", &s, &p);
  64. Init();
  65. for(int i = 0; i < p; ++i) {
  66. scanf("%d%d", &point[i].x, &point[i].y);
  67. for(int j = 0; j < i; ++j) {
  68. node[cnt].u = i;
  69. node[cnt].v = j;
  70. node[cnt].dis = get_dis(i, j);
  71. ++cnt;
  72. }
  73. }
  74. sort(node, node + cnt);
  75. int cnt_ans = 0;
  76. for(int i = 0; i < cnt; ++i) {
  77. int u = node[i].u;
  78. int v = node[i].v;
  79. if(Find(u) != Find(v)) {
  80. ++cnt_ans;
  81. unit(u, v);
  82. if(cnt_ans == p - s) {
  83. ans = sqrt((double)node[i].dis);
  84. break;
  85. }
  86. }
  87. }
  88. printf("%.2f\n", ans);
  89. }
  90. return 0;
  91. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注