有重边与无重边的无向图的割边求法

Posted MekakuCityActor

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了有重边与无重边的无向图的割边求法相关的知识,希望对你有一定的参考价值。

无向图无重边:也就每两个顶点之间最多有一条边相连【也就是根据顶点编号即可确定边】【如下】

无向图有重边如:顶点1与顶点2有两条或更多的边直接相连【也就是不能根据顶点编号来确定边】【如下】

 

首先介绍无重边的无向图的割边求法:由于无重边的无向图中可以根据顶点来确定边,所以函数中的参数 u 和 fa  都是顶点。

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <vector>
 4 using namespace std;
 5 const int N = 1000 + 10;
 6 vector<int> g[N];
 7 int dfs_clock,pre[N];
 8 int cnt;
 9 int dfs(int u, int fa)
10 {
11     int lowu = pre[u] = ++dfs_clock;
12     int i,v,lowv;
13     for(i=0; i<g[u].size(); ++i)
14     {
15         v = g[u][i];
16         if(!pre[v])
17         {
18             lowv = dfs(v,u);
19             lowu = min(lowu,lowv);
20             if(lowv > pre[u])//相对于割点,只把等号给去掉了
21                 cnt++;
22         }
23         else if(v!=fa && pre[v]<lowu)//v!=fa 因为无重边,所以由v != fa来防止一条边的端点反复使用两次,从而避免使原本是桥的边判定为了不是桥,但也正因为它不更新父节点导致了其不能处理重边
24             lowu = pre[v];
25     }
26     return lowu;
27 }
28 int main()
29 {
30     int i,x,y;
31     int n,m;
32     scanf("%d%d",&n,&m);
33     for(i=0; i<m; ++i)
34     {
35         scanf("%d%d",&x,&y);
36         g[x].push_back(y);
37         g[y].push_back(x);
38     }
39     dfs(1,-1);
40 
41     printf("%d\\n",cnt);
42 }

下面是有重边的无向图的割边求法:由于有重边的无向图中不可以根据顶点来确定边,所以函数中的参数 u 是顶点,而 id 是边的编号。

 1 #include"string.h"  
 2 #include"stdio.h"  
 3 #include"iostream"  
 4 #define M 1111  
 5 #define inf 999999999  
 6 using namespace std;  
 7 struct st  
 8 {  
 9     int u,v,w,next;  
10 }edge[M*M*2];  
11 int head[M],dfn[M],low[M],bridge[M],n,t,index,num,mini,flag;  
12 void init()  
13 {  
14     t=0;  
15     memset(head,-1,sizeof(head));  
16 }  
17 void add(int u,int v,int w)  
18 {  
19     edge[t].u=u;  
20     edge[t].v=v;  
21     edge[t].w=w;  
22     edge[t].next=head[u];  
23     head[u]=t++;  
24 }  
25 void tarjan(int u,int id)  
26 {  
27     dfn[u]=low[u]=++index;  
28     int i;  
29     for(i=head[u];i!=-1;i=edge[i].next)  
30     {  
31         if(i==(1^id))continue; //和无重边的无向图通过v!=fa来避免同一条边重复遍历的处理方式不一样,这个是利用一条边的编号的异或关系来避免重复遍历的 
32         int v=edge[i].v;  
33         if(!dfn[v])  
34         {  
35             tarjan(v,i);  
36             low[u]=min(low[u],low[v]);  
37             if(low[v]>dfn[u])  
38             {  
39                 bridge[num++]=i;  
40                 if(mini>edge[i].w)  
41                     mini=edge[i].w;  
42             }  
43   
44         }  
45         else
46         low[u]=min(low[u],dfn[v]);  //由于上面已经对同一条边进行规避了,所以不需要使用多余的判断,直接就能更新了 
47     }  
48 }  
49 void solve()  
50 {  
51     index=num=flag=0;  
52     memset(dfn,0,sizeof(dfn));  
53     memset(low,0,sizeof(low));  
54     for(int i=1;i<=n;i++)  
55     {  
56         if(!dfn[i])  
57         {  
58             flag++;  
59             tarjan(i,-1);  
60         }  
61   
62     }  
63 }  
64 int main()  
65 {  
66     int m;  
67     while(scanf("%d%d",&n,&m),m||n)  
68     {  
69         init();  
70         while(m--)  
71         {  
72             int a,b,c;  
73             scanf("%d%d%d",&a,&b,&c);  
74             add(a,b,c);  
75             add(b,a,c);  
76         }  
77         mini=inf;  
78         solve();  
79         if(flag>1)  
80             printf("0\\n");  
81         else if(num==0)  
82             printf("-1\\n");  
83         else  
84         {  
85             if(mini==0)  
86                 printf("1\\n");  
87             else  
88                 printf("%d\\n",mini);  
89         }  
90     }  
91 }        

 

以上是关于有重边与无重边的无向图的割边求法的主要内容,如果未能解决你的问题,请参考以下文章

ZOJ 2588 Burning Bridges(无向连通图求割边)

Tarjan算法:求解图的割点与桥(割边)

割边 + 缩点(得到边连通分量) + 朴素LCA

POJ 1236 Network of Schools(tarjan算法 + LCA)

hdu-4738(tarjan割边)

[啊哈算法]关键道路(图的割边)