割点和桥
pre[i]为在深搜过程中i被遍历到的顺序序号 low[i] 为i及其后代能连到的最早的祖先
只要u有一个 子结点v存在low[v]>=pre[u]则u是割点 ( 即: v及其后代连不到比u更早的祖先)。
而特殊的 要是low[v]>pre[u] 那么(u,v) 就是桥。因为在算法过程中这条件不止成立一次 所以不能一遇到这给条件就输出 割点或桥
贴个模板先:
1 #include<iostream> 2 #include<vector> 3 #include<string.h> 4 using namespace std; 5 vector < int > g[1002]; 6 int pre[1002],low[1002],iscut[1002],c,vis[1002],hash[1002][1002]; 7 8 int dfs(int u,int p) 9 { 10 int lowu,lowv,child=0; 11 lowu=pre[u]=c++; 12 for(int i=0;i<g[u].size();i++) 13 { 14 15 int v=g[u][i]; 16 if(!pre[v]) 17 { 18 child++; 19 lowv=dfs(v,u); // 子节点的 能连回的最早 祖先节点 20 if(lowv<lowu) 21 lowu=lowv; 22 if(lowv>=pre[u]) // 自己能连回的最早祖先节点 23 iscut[u]=1; 24 } 25 else if(v!=p&&pre[v]<lowu) 26 lowu=pre[v]; 27 if(p<0&&child==1) 28 iscut[u]=0; 29 } 30 low[u]=lowu; 31 return lowu; 32 }
c 在主函数中初始化为 1
(一) 割点
poj 1144 http://poj.org/problem?id=1144 (模板题)
题意:求一个图中有多少个割点 代码就不贴了
poj 1523 SPF http://poj.org/problem?id=1523
题意:给定一个连通网络,网络的结点数<=1000,求出这个网络的所有割点编号,并求出若删去其中一个割点k后,对应的,原网络会被分割为多少个连通分量?
**求删除一个割点i后的连通分支数不必在图中把和点i相关联的边都去掉 照完再补回来 只要 从i的相邻点一个个开始dfs 而不是从点i dfs 就可以了
1 #include<iostream> 2 #include<vector> 3 #include<string.h> 4 using namespace std; 5 vector < int > g[1002]; 6 int pre[1002],low[1002],iscut[1002],c,vis[1002],hash[1002][1002]; 7 8 int dfs(int u,int p) 9 { 10 int lowu,lowv,child=0; 11 lowu=pre[u]=c++; 12 for(int i=0;i<g[u].size();i++) 13 { 14 15 int v=g[u][i]; 16 if(!pre[v]) 17 { 18 child++; 19 lowv=dfs(v,u); // 子节点的 能连回的最早 祖先节点 20 if(lowv<lowu) 21 lowu=lowv; 22 if(lowv>=pre[u]) // 自己能连回的最早祖先节点 23 iscut[u]=1; 24 } 25 else if(v!=p&&pre[v]<lowu) 26 lowu=pre[v]; 27 if(p<0&&child==1) 28 iscut[u]=0; 29 } 30 low[u]=lowu; 31 return lowu; 32 } 33 34 void dfs2(int n,int p) //找连通分支数 35 { 36 vis[n]=1; 37 for(int i=0;i<g[n].size ();i++) 38 { 39 int v; v=g[n][i]; 40 if(v!=p&&!vis[v]) 41 dfs2(v,p); 42 } 43 } 44 int main() 45 { 46 int i,j,m,n,u,v,start,ww=1; 47 while(1) 48 { 49 int temp=0; 50 memset(hash,0,sizeof(hash)); 51 while(scanf("%d",&u)) 52 { 53 if(u==0) 54 break; 55 scanf("%d",&v); 56 if(!hash[u][v]&&!hash[v][u]) 57 { 58 g[u].push_back (v); 59 g[v].push_back (u); 60 temp++; 61 hash[u][v]=1; 62 hash[v][u]=1; 63 } 64 } 65 if(temp==0) 66 break; 67 printf("Network #%d\n",ww++); 68 memset(pre,0,sizeof(pre)); 69 memset(iscut,0,sizeof(iscut)); 70 for(i=1;i<=1000;i++) 71 if(!pre[i]&&g[i].size ()>0) 72 { 73 c=1; 74 dfs(i,-1); 75 } 76 int flag=0; //是不是 有割点 77 for(i=1;i<=1000;i++) 78 { 79 80 if(iscut[i])// 若i是割点 找没有了点i 整个图的连通分支数 81 { 82 memset(vis,0,sizeof(vis)); 83 flag=1; 84 int temp=0; //去掉 i点的 连通分支数 85 for(j=0;j<g[i].size ();j++) 86 if(!vis[g[i][j]]) 87 { 88 temp++; 89 dfs2(g[i][j],i); 90 } 91 printf(" SPF node %d leaves %d subnets\n",i,temp); 92 } 93 } 94 if(flag==0) 95 printf(" No SPF nodes\n"); 96 printf("\n"); 97 for(i=0;i<=1000;i++) 98 g[i].clear (); 99 100 } 101 return 0; 102 }
poj 2117 Electricity http://poj.org/problem?id=2117
题意:一个无向图,现在要去掉其中一个点,要求去掉这个点之后,总连通分支数最大
和上题差不多
1 #include<iostream> 2 #include<vector> 3 #include<string.h> 4 using namespace std; 5 vector < int > g[10002]; 6 int pre[10002],count1,low[100022],iscut[10002],c,vis[10002]; 7 int dfs(int u,int p) 8 { 9 int lowu,lowv,child=0; 10 lowu=pre[u]=c++; 11 for(int i=0;i<g[u].size();i++) 12 { 13 int v=g[u][i]; 14 if(!pre[v]) 15 { 16 child++; 17 lowv=dfs(v,u); // 子节点的 能连回的最早 祖先节点 18 if(lowv<lowu) 19 lowu=lowv; 20 if(lowv>=pre[u]) // 自己能连回的最早祖先节点 21 iscut[u]=1; 22 } 23 else if(v!=p&&pre[v]<lowu) 24 lowu=pre[v]; 25 if(p<0&&child==1) 26 iscut[u]=0; 27 } 28 low[u]=lowu; 29 return lowu; 30 } 31 32 void dfs2(int n,int p) 33 { 34 vis[n]=1; 35 for(int i=0;i<g[n].size ();i++) 36 { 37 int v; v=g[n][i]; 38 if(v!=p&&!vis[v]) 39 dfs2(v,p); 40 } 41 } 42 43 44 int main() 45 { 46 int i,j,m,n,u,v; 47 while(scanf("%d%d",&n,&m)) 48 { 49 if(n==0&&m==0) 50 break; 51 if(m==0) 52 { 53 printf("%d\n",n-1); 54 continue; 55 } 56 while(m--) 57 { 58 scanf("%d%d",&u,&v); 59 g[u].push_back(v); 60 g[v].push_back(u); 61 } 62 memset(pre,0,sizeof(pre)); 63 memset(iscut,0,sizeof(iscut)); 64 count1=0 ; // l连通分支数 65 for(i=0;i<n;i++) 66 if(!pre[i]) 67 { 68 c=1; //一开始c=0; wa 69 count1++; 70 dfs(i,-1); 71 } 72 int ans; ans=count1; 73 for(i=0;i<n;i++) 74 { 75 if(iscut[i]) 76 { 77 memset(vis,0,sizeof(vis)); 78 int temp=0; 79 for(j=0;j<g[i].size ();j++) 80 if(!vis[g[i][j]]) 81 { 82 temp++; 83 dfs2(g[i][j],i); 84 } 85 if(temp-1+count1>ans) 86 ans=temp-1+count1; 87 } 88 } 89 printf("%d\n",ans); 90 for(i=0;i<=n;i++) 91 g[i].clear (); 92 } 93 return 0; 94 }
(二)桥
hdu
1 #include<iostream> 2 #include<stdio.h> 3 #include<string.h> 4 #include<vector> 5 using namespace std; 6 #define INF 10000000 7 int w[1002][1002],cc,uu[10002],vv[10002],pre[1002],low[1002],num,vis[1002],ww[1002][1002],pp; 8 vector <int > g[1002]; 9 10 int dfs(int u,int fa) 11 { 12 int i,child=0; 13 low[u]=pre[u]=num++; 14 int len=g[u].size (); 15 for(i=0;i<len;i++) 16 { 17 int v=g[u][i]; 18 if(!pre[v]) 19 { 20 int lowv=dfs(v,u); 21 if(low[u]>lowv) 22 low[u]=lowv; 23 if(lowv>pre[u]) 24 { 25 if(ww[u][v]==1) 26 { uu[cc]=u; vv[cc++]=v;} 27 } 28 } 29 else if(pre[v]<pre[u]&&pre[v]<low[u]&&v!=fa) 30 low[u]=pre[v]; 31 } 32 return low[u]; 33 } 34 35 void dfs1(int x) 36 { 37 vis[x]=pp; 38 for(int i=0;i<g[x].size ();i++) 39 if(!vis[g[x][i]]) 40 dfs1(g[x][i]); 41 } 42 43 44 int main() 45 { 46 int i,n,m,a,b,c,t=0; 47 while(scanf("%d%d",&n,&m)) 48 { 49 t++;if(t>12) break; 50 if(n==0&&m==0) 51 break; 52 memset(w,-1,sizeof(w)); 53 memset(ww,0,sizeof(ww)); 54 while(m--) 55 { 56 scanf("%d%d%d",&a,&b,&c); 57 w[a][b]=c; 58 ww[a][b]++; 59 ww[b][a]++; 60 g[a].push_back(b); 61 g[b].push_back(a); 62 } 63 pp=1; num=1; cc=0; 64 memset(vis,0,sizeof(vis)); 65 memset(pre,0,sizeof(pre)); 66 67 for(i=1;i<=n;i++) 68 { 69 if(!vis[i]) 70 { 71 dfs1(i); 72 pp++; 73 74 } 75 } 76 if(pp>2) 77 { 78 printf("0\n"); 79 continue; 80 } 81 dfs(1,-1); 82 int ans=INF; 83 for(i=0;i<cc;i++) 84 { 85 //printf("---%d %d\n",uu[i],vv[i]); 86 if(w[uu[i]][vv[i]]<ans) 87 ans=w[uu[i]][vv[i]]; 88 } 89 if(ans==0) 90 ans=1; 91 92 if(cc==0) 93 printf("-1\n"); 94 else 95 printf("%d\n",ans); 96 for(i=0;i<=n;i++) 97 g[i].clear (); 98 99 } 100 return 0; 101 }