[关闭]
@DATASOURCE 2015-09-01T14:19:59.000000Z 字数 12423 阅读 1474

图的连通性问题

图论 连通性


割点的求法(无向图)

  1. void Tarjan(int u, int fa){
  2. int son = 0;
  3. vis[u] = 1;
  4. dfn[u] = low[u] = ++tdfn;
  5. for(int i = head[u]; i + 1; i = edge[i].nxt){
  6. int v = edge[i].v;
  7. if(vis[v] == 1 && v != fa) low[u] = min(low[u], dfn[v]);
  8. if(vis[v]) continue;
  9. Tarjan(v, u);
  10. son++;
  11. low[u] = min(low[u], low[v]);
  12. if((u == root && son > 1) || (u != root && dfn[u] <= low[v])) cut[u] = 1;
  13. }
  14. vis[u] = 2;
  15. }

调用时root = 1, Tarjan(1, -1).

割点删除后图的连通分支数

  1. // 当 cut[i] > 0 时有割点, 并且删除改点后, 图被分成 cut[i] + 1 个连通分量。
  2. void Tarjan(int u){
  3. vis[u] = 1;
  4. int son = 0;
  5. dfn[u] = low[u] = ++tdfn;
  6. for(int i = head[u]; i + 1; i = edge[i].nxt){
  7. int v = edge[i].v;
  8. if(vis[v]) low[u] = min(low[u], dfn[v]);
  9. else{
  10. Tarjan(v);
  11. low[u] = min(low[u], low[v]);
  12. if(dfn[u] <= low[v]) cut[u]++, son++;
  13. }
  14. }
  15. if(u == rt) cut[u] = son - 1 < 0 ? 0 : son - 1;
  16. }

调用时rt = 1, Tarjan(1).

另一种写法

  1. // 当 cut[i] > 0 时有割点, 并且删除改点后, 图被分成 cut[i] + 1 个连通分量。
  2. void Tarjan(int u, int fa){
  3. vis[u] = 1;
  4. int son = 0;
  5. dfn[u] = low[u] = tdfn++;
  6. for(int i = head[u]; i + 1; i = edge[i].nxt){
  7. int v = edge[i].v;
  8. if(vis[v] == 1 && v != fa) low[u] = min(low[u], dfn[v]);
  9. if(vis[v]) continue;
  10. Tarjan(v, u);
  11. son++;
  12. low[u] = min(low[u], low[v]);
  13. if((u == rt && son > 1) || (u != rt && dfn[u] <= low[v])) cut[u]++;
  14. }
  15. vis[u] = 2;
  16. }

调用时rt = 1, Tarjan(1, -1);.

一个例题(POJ 2117)

题意:一个无向图,现在要去掉其中一个点,要求去掉这个点之后,总连通分支数最大。
  1. /*=============================================================================
  2. # Author: He Shuwei
  3. # Last modified: 2015-08-03 20:37
  4. # Filename: POJ_2117_割点.cpp
  5. # Description:
  6. =============================================================================*/
  7. #include <map>
  8. #include <cmath>
  9. #include <queue>
  10. #include <stack>
  11. #include <vector>
  12. #include <cstdio>
  13. #include <string>
  14. #include <cstdlib>
  15. #include <cstring>
  16. #include <iostream>
  17. #include <algorithm>
  18. #define lson l, mid, ls
  19. #define rson mid, r, rs
  20. #define ls (rt << 1) + 1
  21. #define rs (rt << 1) + 2
  22. using namespace std;
  23. const int MAXN = 10100;
  24. struct Edge{
  25. int v, nxt;
  26. };
  27. int root;
  28. int dfn[MAXN];
  29. int low[MAXN];
  30. int cut[MAXN];
  31. int vis[MAXN];
  32. int head[MAXN];
  33. Edge edge[3 * MAXN];
  34. int ecnt, n, m, tdfn;
  35. void init(){
  36. ecnt = 0;
  37. memset(vis, 0, sizeof(vis));
  38. memset(dfn, 0, sizeof(dfn));
  39. memset(cut, 0, sizeof(cut));
  40. memset(low, 0, sizeof(low));
  41. memset(edge, 0, sizeof(edge));
  42. memset(head, -1, sizeof(head));
  43. }
  44. void addEdge(int u, int v){
  45. edge[ecnt].v = v;
  46. edge[ecnt].nxt = head[u];
  47. head[u] = ecnt++;
  48. }
  49. void Tarjan(int u, int fa){
  50. int son = 0;
  51. vis[u] = 1;
  52. dfn[u] = low[u] = ++tdfn;
  53. for(int i = head[u]; i + 1; i = edge[i].nxt){
  54. int v = edge[i].v;
  55. if(vis[v] == 1 && v != fa) low[u] = min(low[u], dfn[v]);
  56. if(vis[v]) continue;
  57. Tarjan(v, u);
  58. son++;
  59. low[u] = min(low[u], low[v]);
  60. if((u == root && son > 1) || (u != root && dfn[u] <= low[v])) cut[u]++;
  61. }
  62. vis[u] = 2;
  63. }
  64. int main(){
  65. while(~scanf("%d%d", &n, &m)){
  66. if(!(n + m)) break;
  67. if(m == 0){
  68. printf("%d\n", n - 1);
  69. continue;
  70. }
  71. init();
  72. int u, v;
  73. for(int i = 0; i < m; i++){
  74. scanf("%d%d", &u, &v);
  75. addEdge(u, v);
  76. addEdge(v, u);
  77. }
  78. int ans = 0;
  79. int res = 0;
  80. for(int i = 0; i < n; i++){
  81. if(!dfn[i]){
  82. ans++;
  83. tdfn = 0;
  84. root = i;
  85. Tarjan(i, -1);
  86. }
  87. res = max(res, cut[i]);
  88. }
  89. printf("%d\n", ans + res);
  90. }
  91. return 0;
  92. }

求割边

  1. // edge[i].id == -1 时, 这条边是重边, 故排除
  2. // 割边的编号保存在 res 数组中。
  3. void addEdge(int u, int v, int id){
  4. for(int i = head[u]; i + 1; i = edge[i].nxt){
  5. if(edge[i].v == v){
  6. edge[i].id = -1;
  7. return;
  8. }
  9. }
  10. edge[ecnt].v = v;
  11. edge[ecnt].id = id;
  12. edge[ecnt].nxt = head[u];
  13. head[u] = ecnt++;
  14. u = u ^ v, v = u ^ v, u = u ^ v;
  15. edge[ecnt].v = v;
  16. edge[ecnt].id = id;
  17. edge[ecnt].nxt = head[u];
  18. head[u] = ecnt++;
  19. }
  20. void Tarjan(int u, int fa){
  21. vis[u] = 1;
  22. dfn[u] = low[u] = ++tdfn;
  23. for(int i = head[u]; i + 1; i = edge[i].nxt){
  24. int v = edge[i].v;
  25. if(vis[v] == 1 && v != fa) low[u] = min(low[u], dfn[v]);
  26. if(vis[v]) continue;
  27. Tarjan(v, u);
  28. low[u] = min(low[u], low[v]);
  29. if(dfn[u] < low[v] && edge[i].id != -1) res[cnt++] = edge[i].id;
  30. }
  31. vis[u] = 2;
  32. }

双联通缩点

  1. void Tarjan(int u, int fa){
  2. sta.push(u);
  3. instack[u] = true;
  4. low[u] = dfn[u] = ++tdfn;
  5. for(int i = head[u]; i + 1; i = edge[i].nxt){
  6. int v = edge[i].v;
  7. if(v == fa) continue;
  8. if(!dfn[v]){
  9. Tarjan(v, u);
  10. low[u] = min(low[u], low[v]);
  11. }else if(instack[v]) low[u] = min(low[u], low[v]);
  12. }
  13. if(dfn[u] == low[u]){
  14. scc++;
  15. int top;
  16. do{
  17. top = sta.top();
  18. sta.pop();
  19. instack[top] = false;
  20. belong[top] = scc;
  21. }while(top != u && !sta.empty());
  22. }
  23. }

调用时

  1. for(int i = 1; i <= n; i++)
  2. if(!dfn[i]) Tarjan(i, -1);

一个例题(poj 3117)

题意:有n个牧场,Bessie 要从一个牧场到另一个牧场,要求至少要有2条独立的路可以走。现已有m条路,求至少要新建多少条路,使得任何两个牧场之间至少有两条独立的路。两条独立的路是指:没有公共边的路,但可以经过同一个中间顶点。

分析:在同一个边双连通分量中,任意两点都有至少两条独立路可达,所以同一个边双连通分量里的所有点可以看做同一个点。

缩点后,新图是一棵树,树的边就是原无向图的桥。

现在问题转化为:在树中至少添加多少条边能使图变为双连通图。

结论:添加边数=(树中度为1的节点数+1)/2

具体方法为,首先把两个最近公共祖先最远的两个叶节点之间连接一条边,这样可以把这两个点到祖先的路径上所有点收缩到一起,因为一个形成的环一定是双连通的。然后再找两个最近公共祖先最远的两个叶节点,这样一对一对找完,恰好是(leaf+1)/2次,把所有点收缩到了一起。

其实求边双连通分量和求强连通分量差不多,每次访问点的时候将其入栈,当low[u]==dfn[u]时就说明找到了一个连通的块,则栈内的所有点都属于同一个边双连通分量,因为无向图要见反向边,所以在求边双连通分量的时候,遇到反向边跳过就行了
  1. /*=============================================================================
  2. # Author: He Shuwei
  3. # Last modified: 2015-08-07 14:37
  4. # Filename: POJ_3177_3352_双连通图+缩点.cpp
  5. # Description:
  6. =============================================================================*/
  7. #include <map>
  8. #include <cmath>
  9. #include <queue>
  10. #include <stack>
  11. #include <vector>
  12. #include <cstdio>
  13. #include <string>
  14. #include <cstdlib>
  15. #include <cstring>
  16. #include <iostream>
  17. #include <algorithm>
  18. #define lson l, mid, ls
  19. #define rson mid, r, rs
  20. #define ls (rt << 1) + 1
  21. #define rs (rt << 1) + 2
  22. using namespace std;
  23. const int MAXN = 5050;
  24. const int MAXE = 20020;
  25. struct Edge{
  26. int v, nxt;
  27. };
  28. Edge edge[MAXE];
  29. stack <int> sta;
  30. bool instack[MAXN];
  31. int ecnt, n, m, scc, tdfn;
  32. int degree[MAXN], belong[MAXN];
  33. int head[MAXN], dfn[MAXN], low[MAXN];
  34. void init(){
  35. ecnt = scc = tdfn = 0;
  36. while(!sta.empty()) sta.pop();
  37. memset(dfn, 0, sizeof(dfn));
  38. memset(low, 0, sizeof(low));
  39. memset(edge, 0, sizeof(edge));
  40. memset(head, -1, sizeof(head));
  41. memset(degree, 0, sizeof(degree));
  42. memset(instack, 0, sizeof(instack));
  43. }
  44. void addEdge(int u, int v){
  45. edge[ecnt].v = v;
  46. edge[ecnt].nxt = head[u];
  47. head[u] = ecnt++;
  48. }
  49. void Tarjan(int u, int fa){
  50. sta.push(u);
  51. instack[u] = true;
  52. low[u] = dfn[u] = ++tdfn;
  53. for(int i = head[u]; i + 1; i = edge[i].nxt){
  54. int v = edge[i].v;
  55. if(v == fa) continue;
  56. if(!dfn[v]){
  57. Tarjan(v, u);
  58. low[u] = min(low[u], low[v]);
  59. }else if(instack[v]) low[u] = min(low[u], low[v]);
  60. }
  61. if(dfn[u] == low[u]){
  62. scc++;
  63. int top;
  64. do{
  65. top = sta.top();
  66. sta.pop();
  67. instack[top] = false;
  68. belong[top] = scc;
  69. }while(top != u && !sta.empty());
  70. }
  71. }
  72. int solve(){
  73. for(int i = 1; i <= n; i ++)
  74. if(!dfn[i]) Tarjan(1, -1);
  75. for(int i = 1; i <= n; i++){
  76. for(int j = head[i]; j + 1; j = edge[j].nxt){
  77. int v = edge[j].v;
  78. if(belong[i] != belong[v]) degree[belong[i]]++;
  79. }
  80. }
  81. int res = 0;
  82. for(int i = 1; i <= n; i++)
  83. if(degree[i] == 1) res++;
  84. int ans = (res + 1) / 2;
  85. return ans;
  86. }
  87. int main(){
  88. while(scanf("%d%d", &n, &m) != EOF){
  89. init();
  90. int u, v;
  91. for(int i = 0; i < m; i++){
  92. scanf("%d%d", &u, &v);
  93. addEdge(u, v);
  94. addEdge(v, u);
  95. }
  96. int ans = solve();
  97. printf("%d\n", ans);
  98. }
  99. return 0;
  100. }

强连通分量

解法一

  1. void dfs(int u){
  2. vis[u] = true;
  3. for(int i = head[u]; i + 1; i = edge[i].nxt)
  4. if(!vis[edge[i].v]) dfs(edge[i].v);
  5. vs[vscnt++] = u;
  6. }
  7. void rdfs(int u, int k){
  8. vis[u] = true;
  9. cmp[u] = k;
  10. for(int i = rhead[u]; i + 1; i = redge[i].nxt)
  11. if(!vis[redge[i].v]) rdfs(redge[i].v, k);
  12. }
  13. int scc(){
  14. memset(vis, 0, sizeof(vis));
  15. vscnt = 0;
  16. for(int i = 1; i <= n; i++)
  17. if(!vis[i]) dfs(i);
  18. int scc_cnt = 0;
  19. memset(vis, 0, sizeof(vis));
  20. for(int i = vscnt - 1; i >= 0; i--)
  21. if(!vis[vs[i]]) rdfs(vs[i], scc_cnt++);
  22. return scc_cnt;
  23. }

解法二

  1. void Tarjan(int u){
  2. sta.push(u);
  3. instack[u] = true;
  4. dfn[u] = low[u] = ++tdfn;
  5. for(int i = head[u]; i + 1; i = edge[i].nxt){
  6. int v = edge[i].v;
  7. if(dfn[v] == 0){
  8. Tarjan(v);
  9. low[u] = min(low[u], low[v]);
  10. }else if(instack[v]) low[u] = min(low[u], low[v]);
  11. }
  12. if(low[u] == dfn[u]){
  13. int top;
  14. scc_cnt++;
  15. do{
  16. top = sta.top();
  17. sta.pop();
  18. instack[top] = false;
  19. belong[top] = scc_cnt;
  20. }while(u != top && !sta.empty());
  21. }
  22. }

调用方法

  1. for(int i = 1; i <= n; i++)
  2. if(!dfn[i]) Tarjan(i);

几个例题

HDU 4635

题意:最多加多少条边,使得原图不是强连通图

正向考虑有困难,不妨反向思考,既最少去掉几条边使得原图不是强连通。

总边数sum=n*(n-1)时肯定是强连通,已经给了m条边,sum-=m

这时把已经强连通的部分进行缩点,对于缩好的点我们把他们分成两部分,保证其中一部分到另一部分没有边(这两部分不强连通),再把sum减去两部分能构成所有的边数,取最大值即为答案

具体做时枚举每个小强连通块,找到num[i]*(n-num[i])最小的情况(num[i]为小强连通块点数),其中必须出度或入度为0的连通块才可以被选择
  1. /*=============================================================================
  2. # Author: He Shuwei
  3. # Last modified: 2015-08-08 15:47
  4. # Filename: HDU_4635_加最多边使不强连通.cpp
  5. # Description:
  6. =============================================================================*/
  7. #include <map>
  8. #include <cmath>
  9. #include <queue>
  10. #include <stack>
  11. #include <vector>
  12. #include <cstdio>
  13. #include <string>
  14. #include <cstdlib>
  15. #include <cstring>
  16. #include <iostream>
  17. #include <algorithm>
  18. #define lson l, mid, ls
  19. #define rson mid, r, rs
  20. #define ls (rt << 1) + 1
  21. #define rs (rt << 1) + 2
  22. using namespace std;
  23. const int MAXN = 100020;
  24. const int MAXE = 200010;
  25. struct Edge{
  26. int v, nxt;
  27. };
  28. bool vis[MAXN];
  29. Edge edge[MAXE], redge[MAXE];
  30. int n, m, ecnt, recnt, vs_cnt, scc_cnt;
  31. int head[MAXN], rhead[MAXN], vs[MAXN], belong[MAXN], In[MAXN], Out[MAXN], num[MAXN];
  32. void init(){
  33. ecnt = recnt = vs_cnt = scc_cnt = 0;
  34. memset(In, 0, sizeof(In));
  35. memset(Out, 0, sizeof(Out));
  36. memset(num, 0, sizeof(num));
  37. memset(edge, 0, sizeof(edge));
  38. memset(head, -1, sizeof(head));
  39. memset(redge, 0, sizeof(redge));
  40. memset(rhead, -1, sizeof(rhead));
  41. }
  42. void addEdge(int *head, Edge *edge, int u, int v, int &cnt){
  43. edge[cnt].v = v;
  44. edge[cnt].nxt = head[u];
  45. head[u] = cnt++;
  46. }
  47. void dfs(int u){
  48. vis[u] = true;
  49. for(int i = head[u]; i + 1; i = edge[i].nxt){
  50. if(!vis[edge[i].v]) dfs(edge[i].v);
  51. }
  52. vs[vs_cnt++] = u;
  53. }
  54. void rdfs(int u, int k){
  55. vis[u] = true;
  56. belong[u] = k;
  57. for(int i = rhead[u]; i + 1; i = redge[i].nxt){
  58. if(!vis[redge[i].v]) rdfs(redge[i].v, k);
  59. }
  60. }
  61. void scc(){
  62. memset(vis, 0, sizeof(vis));
  63. for(int i = 1; i <= n; i++)
  64. if(!vis[i]) dfs(i);
  65. memset(vis, 0, sizeof(vis));
  66. for(int i = vs_cnt - 1; i >= 0; i--)
  67. if(!vis[vs[i]]) rdfs(vs[i], scc_cnt++);
  68. }
  69. void calDegree(){
  70. for(int u = 1; u <= n; u++){
  71. for(int i = head[u]; i + 1; i = edge[i].nxt){
  72. int v = edge[i].v;
  73. if(belong[u] != belong[v]) In[belong[v]]++, Out[belong[u]]++;
  74. }
  75. }
  76. }
  77. long long solve(){
  78. scc();
  79. calDegree();
  80. for(int i = 1; i <= n; i++)
  81. num[belong[i]]++;
  82. long long sss = (long long)n * (n - 1) - m;
  83. long long ans = 0;
  84. for(int i = 0; i < scc_cnt; i++)
  85. if(In[i] == 0 || Out[i] == 0)
  86. ans = max(ans, sss - (long long)num[i] * (n - num[i]));
  87. return scc_cnt == 1 ? -1 : ans;
  88. }
  89. int main(){
  90. int t;
  91. scanf("%d", &t);
  92. for(int Case = 1; Case <= t; Case++){
  93. init();
  94. scanf("%d%d", &n, &m);
  95. int u, v;
  96. for(int i = 0; i < m; i++){
  97. scanf("%d%d", &u, &v);
  98. addEdge(head, edge, u, v, ecnt);
  99. addEdge(rhead, redge, v, u, recnt);
  100. }
  101. long long ans = solve();
  102. printf("Case %d: %lld\n", Case, ans);
  103. }
  104. return 0;
  105. }

POJ3592

题目大意:

    给出一个n*m的格子地图,每一格上面是0~9,“*”或“#”。如果格子上是数字代表这个格子上有当前数量的矿石。如果是“*” 代表着当前格子是一个传送阵可以传送到指定的地方。如果是“#”代表当前格子不可达。

    现在有一个矿车在坐标(0,0),也就是左上角。他只能向右和下行驶。当遇到传送阵时可以被传送到指定的位置。当他遇到数字时就可以得到那些数量的矿石,那个地方的矿石数量就变为“0”。问矿车最多可以采多少矿。

解题思路:

    1、我们先要根据格子地图建图。(注1)

    2、因为建立出的图可能会有环,我们要用Tarjan算法将环缩成点。(注2)

    3、我们将缩点处理后的图重新建图。(注3)

    4、对图求最长路。
  1. /*=============================================================================
  2. # Author: He Shuwei
  3. # Last modified: 2015-08-12 10:35
  4. # Filename: POJ_3592_缩点+SPFA.cpp
  5. # Description:
  6. =============================================================================*/
  7. #include <map>
  8. #include <cmath>
  9. #include <queue>
  10. #include <stack>
  11. #include <vector>
  12. #include <cstdio>
  13. #include <string>
  14. #include <cstdlib>
  15. #include <cstring>
  16. #include <iostream>
  17. #include <algorithm>
  18. #define lson l, mid, ls
  19. #define rson mid, r, rs
  20. #define ls (rt << 1) + 1
  21. #define rs (rt << 1) + 2
  22. using namespace std;
  23. const int MAXN = 2000;
  24. const int MAXE = 5000;
  25. struct Edge{
  26. int v, nxt;
  27. };
  28. char mp[MAXN][MAXN];
  29. Edge edge[MAXE];
  30. stack <int> sta;
  31. bool instack[MAXN];
  32. int n, m, scc_cnt, ecnt, tdfn;
  33. int head[MAXN], val[MAXN], dfn[MAXN], low[MAXN], belong[MAXN];
  34. int scnt;
  35. bool vis[MAXN];
  36. Edge sedge[MAXE];
  37. int shead[MAXN], sccval[MAXN], dis[MAXN];
  38. void init(){
  39. scc_cnt = ecnt = tdfn = scnt = 0;
  40. memset(vis, 0, sizeof(vis));
  41. memset(dis, 0, sizeof(dis));
  42. memset(val, 0, sizeof(val));
  43. memset(dfn, 0, sizeof(dfn));
  44. memset(low, 0, sizeof(low));
  45. while(!sta.empty()) sta.pop();
  46. memset(edge, 0, sizeof(edge));
  47. memset(head, -1, sizeof(head));
  48. memset(sedge, 0, sizeof(sedge));
  49. memset(shead, -1, sizeof(shead));
  50. memset(sccval, 0, sizeof(sccval));
  51. memset(belong, 0, sizeof(belong));
  52. memset(instack, 0, sizeof(instack));
  53. }
  54. void addEdge(int *head, Edge *edge, int u, int v, int &cnt){
  55. edge[cnt].v = v;
  56. edge[cnt].nxt = head[u];
  57. head[u] = cnt++;
  58. }
  59. void Input(){
  60. scanf("%d%d", &n, &m);
  61. for(int i = 0; i < n; i++)
  62. scanf("%s", mp[i]);
  63. int a, b;
  64. for(int i = 0; i < n; i++)
  65. for(int j = 0; j < m; j++){
  66. if(mp[i][j] == '#') continue;
  67. if(mp[i][j] >= '0' && mp[i][j] <= '9') val[m * i + j] = mp[i][j] - '0';
  68. else if(mp[i][j] == '*'){
  69. scanf("%d%d", &a, &b);
  70. addEdge(head, edge, m * i + j, a * m + b, ecnt);
  71. }
  72. if(i + 1 < n && mp[i + 1][j] != '#')
  73. addEdge(head, edge, m * i + j, m * (i + 1) + j, ecnt);
  74. if(j + 1 < m && mp[i][j + 1] != '#')
  75. addEdge(head, edge, m * i + j, m * i + j + 1, ecnt);
  76. }
  77. //for(int i = 0; i < n * m; i++)
  78. //cerr <<"i = "<< i <<", val[i] = "<< val[i] << endl;
  79. }
  80. void Tarjan(int u){
  81. sta.push(u);
  82. instack[u] = true;
  83. dfn[u] = low[u] = ++tdfn;
  84. for(int i = head[u]; i + 1; i = edge[i].nxt){
  85. int v = edge[i].v;
  86. if(!dfn[v]){
  87. Tarjan(v);
  88. low[u] = min(low[u], low[v]);
  89. }else if(instack[v]) low[u] = min(low[u], low[v]);
  90. }
  91. if(low[u] == dfn[u]){
  92. ++scc_cnt;
  93. int top;
  94. do{
  95. top = sta.top();
  96. sta.pop();
  97. instack[top] = false;
  98. belong[top] = scc_cnt;
  99. sccval[scc_cnt] += val[top];
  100. //cerr <<"scc_cnt = "<< scc_cnt <<", top = "<< top <<", val[top] = "<< val[top] <<", sccval[scc_cnt] = "<< sccval[scc_cnt] << endl;
  101. }while(top != u && !sta.empty());
  102. }
  103. }
  104. void SPFA(int src){
  105. queue <int> que;
  106. que.push(src);
  107. vis[src] = true;
  108. dis[src] = sccval[src];
  109. while(!que.empty()){
  110. int u = que.front();
  111. que.pop();
  112. vis[u] = false;
  113. for(int i = shead[u]; i + 1; i = sedge[i].nxt){
  114. int v = sedge[i].v;
  115. dis[v] = max(dis[v], dis[u] + sccval[v]);
  116. if(!vis[v]) que.push(v), vis[v] = true;
  117. }
  118. }
  119. }
  120. void solve(){
  121. for(int i = 0; i < n * m; i++)
  122. if(!dfn[i]) Tarjan(i);
  123. //cerr <<"scc_cnt = "<< scc_cnt << endl;
  124. //for(int i = 0; i < n * m; i++)
  125. //cerr <<"i = "<< i <<", belong[i] = "<< belong[i] <<", sccval[belong[i]] = "<< sccval[belong[i]] << endl;
  126. for(int u = 0; u < n * m; u++)
  127. for(int i = head[u]; i + 1; i = edge[i].nxt){
  128. int v = edge[i].v;
  129. if(belong[u] != belong[v]) addEdge(shead, sedge, belong[u], belong[v], scnt);
  130. }
  131. SPFA(belong[0]);
  132. int ans = 0;
  133. for(int i = 1; i <= scc_cnt; i++)
  134. ans = max(ans, dis[i]);
  135. printf("%d\n", ans);
  136. }
  137. int main(){
  138. int t;
  139. scanf("%d", &t);
  140. while(t--){
  141. init();
  142. Input();
  143. solve();
  144. }
  145. return 0;
  146. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注