poj 3177 & 3352 【无向图双连通分量Tarjan】

Bertha 。 2022-08-13 15:47 240阅读 0赞

题目:poj 3177 & 3352

题意:大概意思就是给你一个无向图,让你添加最少的边,让所有点都双连通。

分析:双连通的定义就是任意两个点至少有两条路可达。

其实做法跟添加最少边强连通一样,先对图中已经双连通的缩点,然后重新编号。

这就是著名的Tanjan算法。

通过搜索的思想对所有存在环的边遍相同的号

如果要让所有的点双连通,那么对于缩点后的图中如果度数为 1 的话,这些边肯定要连接到其他的点才能双连通,而题目要求添加最少,所以连接到其他度数也为 1 的点是最优的,那么答案就是(odd+1)/ 2

注意:图中存在重边,所以要判重。

AC代码:

  1. #include <iostream>
  2. #include <algorithm>
  3. #include <string>
  4. #include <math.h>
  5. #include <vector>
  6. #include <cstring>
  7. #include <cstdio>
  8. #include <stack>
  9. using namespace std;
  10. #define Del(a,b) memset(a,b,sizeof(a))
  11. const int N = 1100;
  12. const int inf = 0x3f3f3f3f;
  13. int vis[N],dfn[N],low[N];
  14. vector<int> v[N];
  15. struct Node
  16. {
  17. int from,to;
  18. };
  19. int bcc_cnt;
  20. stack<Node> s;
  21. void add_Node(int x,int y)
  22. {
  23. v[x].push_back(y);
  24. v[y].push_back(x);
  25. }
  26. void Tarjan(int u,int fa)
  27. {
  28. vis[u]=1;
  29. dfn[u]=low[u]=++bcc_cnt;
  30. for(int i=0;i<v[u].size();i++)
  31. {
  32. int to=v[u][i];
  33. if(vis[to]==1 && to!=fa) //假如与其联通的点访问过了
  34. low[u]=min(low[u],dfn[to]);
  35. if(!vis[to])
  36. {
  37. Tarjan(to,u);
  38. low[u]=min(low[u],low[to]);
  39. }
  40. }
  41. vis[u]=2;
  42. }
  43. int in[N];
  44. int Yougth(int n)
  45. {
  46. Del(in,0);
  47. for(int i=0; i<n; i++)
  48. {
  49. for(int j=0; j<v[i].size(); j++)
  50. {
  51. int to = v[i][j];
  52. //printf("%d %d %d %d\n",i+1,to+1,low[i],low[to]);
  53. if(low[i]!=low[to])
  54. {
  55. in[low[i]]++;
  56. }
  57. }
  58. }
  59. int ans = 0;
  60. for(int i = 1;i<=bcc_cnt;i++)
  61. if(in[i]==1)
  62. ans++;
  63. return (ans+1)/2;
  64. }
  65. void Clear(int x)
  66. {
  67. for(int i=0;i<x;i++)
  68. v[i].clear();
  69. }
  70. int main()
  71. {
  72. //freopen("Input.txt","r",stdin);
  73. int n,m;
  74. string s1,s2,cas;
  75. while(cin>>s1>>s2>>cas)
  76. {
  77. scanf("%d%d",&n,&m);
  78. for(int i=0; i<m; i++)
  79. {
  80. int x,y;
  81. scanf("%d%d",&x,&y);
  82. int ok = 0;
  83. for(int j=0;j<v[x-1].size();j++)
  84. if(v[x-1][j]==(y-1)){
  85. ok = 1;
  86. break;
  87. }
  88. if(ok)
  89. continue;
  90. add_Node(x-1,y-1);
  91. }
  92. cout<<"Output for "<<s1<<" "<<s2<<" "<<cas<<endl;
  93. Del(vis,0),Del(dfn,0),Del(low,0);
  94. bcc_cnt = 0;
  95. Tarjan(0,1);
  96. printf("%d\n\n",Yougth(n));
  97. Clear(n);
  98. }
  99. return 0;
  100. }

发表评论

表情:
评论列表 (有 0 条评论,240人围观)

还没有评论,来说两句吧...

相关阅读

    相关 浅谈连通分量、强连通分量

    初谈这个话题相信每一位都会感到一丝疑惑,主要原因是这个词中“分量”一词,当然,如果仅是为了了解和使用这两个术语,就不必在意这个无关大体的词语。         好了,该谈谈正