圖的割點與橋:node
dfs樹的割點程序代碼:ios
原解釋裏面是錯的。ide
1 #include <iostream> 2 #include <cstdio> 3 4 using namespace std; 5 6 bool adj[10][10]; 7 int visit[10]; 8 int grand[10]; 9 10 int t=0; 11 12 void DFS(int p,int i) 13 { 14 visit[i]=++t; 15 grand[i]=i; 16 17 int child=0; 18 bool ap=false; 19 20 for(int j=0;j<10;j++) 21 if(adj[i][j] && j!=p) 22 { 23 if(visit[j]) 24 { 25 if(visit[j]<visit[grand[i]]) 26 grand[i]=j; 27 } 28 else 29 { 30 child++; 31 DFS(i,j); 32 33 if(visit[grand[i]]>visit[grand[j]]) 34 grand[i]=grand[j]; 35 36 if(visit[grand[j]]>=visit[i]) 37 ap=true; 38 } 39 } 40 41 if((i==p && child>1) || (i!=p && ap)) 42 cout<<"第"<<i<<"點是關節點"<<endl; 43 } 44 45 void articulation_vertex() 46 { 47 memset(visit,0,sizeof(visit)); 48 49 t=0; 50 51 for(int i=0;i<10;i++) 52 if(!visit[i]) 53 DFS(i,i); 54 } 55 56 int main() 57 { 58 int a,b; 59 memset(adj,0,sizeof(adj)); 60 for(int i=0;i<11;i++) 61 { 62 scanf("%d%d",&a,&b); 63 adj[a][b]=adj[b][a]=1; 64 } 65 articulation_vertex(); 66 return 0; 67 }
記錄遍歷順序值spa
1 #include <iostream> 2 #include <cstdio> 3 4 using namespace std; 5 6 bool adj[10][10]; 7 int visit[10]; 8 int low[10]; 9 10 int t=0; 11 12 void DFS(int p,int i) 13 { 14 visit[i]=low[i]=++t; 15 16 int child=0; 17 bool ap=false; 18 19 for(int j=0;j<10;j++) 20 if(adj[i][j] && j!=p) 21 { 22 if(visit[j]) 23 { 24 low[i]=min(low[i],visit[j]); 25 } 26 else 27 { 28 child++; 29 DFS(i,j); 30 31 low[i]=min(low[i],low[j]); 32 33 if(low[j]>=visit[i]) 34 ap=true; 35 } 36 } 37 38 if((i==p && child>1) || (i!=p && ap)) 39 cout<<"第"<<i<<"點是關節點"<<endl; 40 } 41 42 void articulation_vertex() 43 { 44 memset(visit,0,sizeof(visit)); 45 46 t=0; 47 48 for(int i=0;i<10;i++) 49 if(!visit[i]) 50 DFS(i,i); 51 } 52 53 int main() 54 { 55 int a,b; 56 memset(adj,0,sizeof(adj)); 57 for(int i=0;i<11;i++) 58 { 59 scanf("%d%d",&a,&b); 60 adj[a][b]=adj[b][a]=1; 61 } 62 articulation_vertex(); 63 return 0; 64 }
1 #include <iostream> 2 #include <cstdio> 3 4 using namespace std; 5 6 int visit[10]; 7 int low[10]; 8 int adj[10][10]; 9 int parent[10]; 10 int t; 11 12 void DFS(int i) 13 { 14 visit[i]=low[i]=++t; 15 16 for(int j=0;j<10;j++) 17 { 18 if(adj[i][j]) 19 { 20 if(!visit[j]) 21 { 22 parent[j]=i; 23 DFS(j); 24 low[i]=min(low[i],low[j]); 25 } 26 else if(parent[i]!=j) 27 low[i]=min(low[i],visit[j]); 28 } 29 } 30 } 31 32 void articulation_vertex() 33 { 34 memset(visit,0,sizeof(visit)); 35 t=0; 36 for(int i=0;i<10;i++) 37 { 38 if(!visit[i]) 39 { 40 parent[i]=i; 41 DFS(i); 42 } 43 } 44 45 for(int i=0;i<10;i++) 46 { 47 if(i==parent[i]) 48 { 49 int child=0; 50 for(int j=0;j<10;j++) 51 if(parent[j]==i && i!=j) 52 child++; 53 if(child>1) 54 cout<<"Articulation Vertex:"<<i<<endl; 55 } 56 else 57 { 58 bool ap=false; 59 for(int j=0;j<10;j++) 60 if(parent[j]==i && low[j]>=visit[i]) 61 ap=true; 62 if(ap) 63 cout<<"Articulation Vertex:"<<i<<endl; 64 65 } 66 } 67 } 68 69 int main() 70 { 71 int a,b; 72 memset(adj,0,sizeof(adj)); 73 for(int i=0;i<11;i++) 74 { 75 scanf("%d%d",&a,&b); 76 adj[a][b]=adj[b][a]=1; 77 } 78 articulation_vertex(); 79 return 0; 80 }
1 #include <iostream> 2 #include <cstdio> 3 4 using namespace std; 5 6 7 int adj[10][10]; 8 int visit[10]; 9 int low[10]; 10 11 int t=0; 12 13 void DFS(int p,int i) 14 { 15 visit[i]=low[i]=++t; 16 17 for(int j=0;j<10;j++) 18 if(adj[i][j]) 19 { 20 if(!visit[j]) 21 { 22 DFS(i,j); 23 24 low[i]=min(low[i],low[j]); 25 26 if(low[j]>visit[i]) 27 cout<<"bridge:"<<i<<"---"<<j<<endl; 28 } 29 else if(j!=p || (j==p && adj[i][j]>=2)) 30 { 31 low[i]=min(low[i],low[j]); 32 } 33 } 34 } 35 36 void bridge() 37 { 38 memset(visit,0,sizeof(visit)); 39 t=0; 40 41 for(int i=0;i<10;i++) 42 if(!visit[i]) 43 DFS(i,i); 44 } 45 46 int main() 47 { 48 int a,b; 49 memset(adj,0,sizeof(adj)); 50 for(int i=0;i<11;i++) 51 { 52 scanf("%d%d",&a,&b); 53 adj[a][b]=adj[b][a]=1; 54 } 55 bridge(); 56 return 0; 57 58 }
程序代碼分割爲兩段後的.net
1 1 2 2 1 0 3 1 3 4 3 4 5 4 0 6 0 5 7 5 7 8 5 6 9 6 7 10 7 8 11 7 9
poj,36943d
tarjan求出橋,而後並查集縮點,最後成爲一棵樹,而後樹邊即爲橋邊,而後添邊,若是u,v在一個集合中就不要緊。code
若是u,v在兩個集合中就要對這兩個集合間的集合縮點,每縮一次點就減小一次橋邊。blog
1 #include <iostream> 2 #include <cmath> 3 #include <vector> 4 #include <cstdlib> 5 #include <cstdio> 6 #include <cstring> 7 #include <queue> 8 #include <stack> 9 #include <list> 10 #include <algorithm> 11 #include <map> 12 #include <set> 13 #define LL long long 14 #define Pr pair<int,int> 15 16 using namespace std; 17 const int INF=0x3f3f3f3f; 18 const int msz=100000; 19 const int mod=1e9+7; 20 const double eps=1e-8; 21 22 struct Edge 23 { 24 int v,next; 25 }; 26 27 Edge eg[666666]; 28 int head[233333]; 29 int dfn[233333],low[233333]; 30 int pre[233333]; 31 int fa[233333]; 32 bool vis[233333]; 33 int tp,tim; 34 int ans; 35 36 void init(int n) 37 { 38 for(int i=1;i<=n;i++) 39 pre[i]=i; 40 } 41 42 int Find(int x) 43 { 44 return pre[x]==x?x:pre[x]=Find(pre[x]); 45 } 46 47 int Union(int u,int v) 48 { 49 int k=Find(u); 50 int r=Find(v); 51 if(k==r) return false; 52 pre[k]=r; 53 return true; 54 } 55 56 void Tarjan(int u,int p) 57 { 58 vis[u]=1; 59 dfn[u]=low[u]=tim++; 60 int v; 61 62 for(int i=head[u];i!=-1;i=eg[i].next) 63 { 64 v=eg[i].v; 65 if(v==p) continue; 66 67 if(!vis[v]) 68 { 69 fa[v]=u; 70 Tarjan(v,u); 71 low[u]=min(low[u],low[v]); 72 73 if(low[v]>dfn[u]) 74 { 75 ans++; 76 } 77 else 78 Union(v,u); 79 } 80 else low[u]=min(low[u],dfn[v]); 81 } 82 } 83 84 void lca(int u,int v) 85 { 86 if(dfn[v]<dfn[u]) swap(u,v); 87 88 while(dfn[v]>dfn[u]) 89 { 90 if(Union(v,fa[v])) 91 ans--; 92 v=fa[v]; 93 } 94 95 while(v!=u) 96 { 97 if(Union(u,fa[u])) 98 ans--; 99 u=fa[u]; 100 } 101 } 102 103 int main() 104 { 105 int n,m,u,v,z=0; 106 107 while(scanf("%d%d",&n,&m),n+m) 108 { 109 memset(head,-1,sizeof(head)); 110 tim=tp=0; 111 init(n); 112 113 while(m--) 114 { 115 scanf("%d%d",&u,&v); 116 eg[tp].v=v; 117 eg[tp].next=head[u]; 118 head[u]=tp++; 119 120 eg[tp].v=u; 121 eg[tp].next=head[v]; 122 head[v]=tp++; 123 } 124 125 memset(vis,0,sizeof(vis)); 126 ans=0; 127 fa[1]=1; 128 Tarjan(1,1); 129 130 int q; 131 scanf("%d",&q); 132 133 printf("Case %d:\n",++z); 134 135 while(q--) 136 { 137 scanf("%d%d",&u,&v); 138 lca(u,v); 139 printf("%d\n",ans); 140 } 141 puts(""); 142 } 143 return 0; 144 }
poj,3713排序
判斷三聯通問題,先刪除一個點,而後求是否存在割點,若是存在則不是三聯通。get
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <algorithm> 5 6 using namespace std; 7 8 #define maxn 505 9 10 struct edge 11 { 12 int v,next; 13 }; 14 15 edge E[200005]; 16 int head[maxn]; 17 int dfn[maxn],low[maxn]; 18 int vis[maxn]; 19 int tp,tim; 20 int n,m; 21 bool has_cut_vertex; 22 int root; 23 24 void add_edge(int u,int v) 25 { 26 E[tp].v=v; 27 E[tp].next=head[u]; 28 head[u]=tp++; 29 } 30 31 void Tarjan(int u,int p)//求割點/判斷是否聯通 32 { 33 vis[u]=1; 34 dfn[u]=low[u]=++tim; 35 36 int v; 37 int child=0; 38 39 for(int i=head[u];i!=-1;i=E[i].next) 40 { 41 v=E[i].v; 42 if(v==p) continue; 43 44 if(!vis[v]) 45 { 46 Tarjan(v,u); 47 child++; 48 low[u]=min(low[u],low[v]); 49 50 if((u==root && child>1) || (u!=root && low[v]>=dfn[u])) 51 has_cut_vertex=true; 52 } 53 else if(v!=p && vis[v]==1) 54 low[u]=min(low[u],dfn[v]); 55 } 56 vis[u]=2; 57 } 58 59 void calc(int u) 60 {//初始化 61 memset(vis,0,sizeof(vis)); 62 memset(dfn,0,sizeof(dfn)); 63 memset(low,0,sizeof(low)); 64 //每次刪除一個點,而後再看有無割點,若是刪除一個點以後有割點,說明小於三聯通。 65 root=0; 66 if(u==0) 67 { 68 root=1; 69 } 70 vis[u]=2; 71 Tarjan(root,-1); 72 } 73 74 bool solve() 75 { 76 for(int i=0;i<n;i++) 77 { 78 calc(i); 79 80 for(int j=0;j<n;j++) 81 if(vis[j]==0)//若是存在孤立點也不是三聯通 82 { 83 has_cut_vertex=true; 84 break; 85 } 86 if(has_cut_vertex) 87 break; 88 } 89 return !has_cut_vertex; 90 } 91 92 int main() 93 { 94 int u,v; 95 while(scanf("%d%d",&n,&m),n+m) 96 { 97 tp=tim=0; 98 memset(head,-1,sizeof(head)); 99 for(int i=0;i<m;i++) 100 { 101 scanf("%d%d",&u,&v); 102 add_edge(u,v); 103 add_edge(v,u); 104 } 105 106 has_cut_vertex=false; 107 if(solve()) 108 printf("YES\n"); 109 else 110 printf("NO\n"); 111 } 112 return 0; 113 }
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 5 using namespace std; 6 7 #define maxn 505 8 9 struct edge 10 { 11 int v,next; 12 }; 13 14 edge E[200005]; 15 int head[maxn]; 16 int dfn[maxn],low[maxn]; 17 int vis[maxn]; 18 int tp; 19 int n,m; 20 bool has_cut_vertex; 21 int root; 22 23 void add_edge(int u,int v) 24 { 25 E[tp].v=v; 26 E[tp].next=head[u]; 27 head[u]=tp++; 28 } 29 30 void Tarjan(int u,int p,int depth) 31 { 32 vis[u]=1; 33 dfn[u]=low[u]=depth; 34 35 int v; 36 int child=0; 37 38 for(int i=head[u];i!=-1;i=E[i].next) 39 { 40 v=E[i].v; 41 if(v==p) continue; 42 43 if(!vis[v]) 44 { 45 Tarjan(v,u,depth+1); 46 child++; 47 low[u]=min(low[u],low[v]); 48 49 if((u==root && child>1) || (u!=root && low[v]>=dfn[u])) 50 has_cut_vertex=true; 51 } 52 else if(v!=p && vis[v]==1) 53 low[u]=min(low[u],dfn[v]); 54 } 55 vis[u]=2; 56 } 57 58 void calc(int u) 59 { 60 memset(vis,0,sizeof(vis)); 61 memset(dfn,0,sizeof(dfn)); 62 memset(low,0,sizeof(low)); 63 64 root=0; 65 if(u==0) 66 { 67 root=1; 68 } 69 vis[u]=2; 70 Tarjan(root,-1,1); 71 } 72 73 bool solve() 74 { 75 for(int i=0;i<n;i++) 76 { 77 calc(i); 78 79 for(int j=0;j<n;j++) 80 if(vis[j]==0) 81 { 82 has_cut_vertex=true; 83 break; 84 } 85 if(has_cut_vertex) 86 break; 87 } 88 return !has_cut_vertex; 89 } 90 91 int main() 92 { 93 int u,v; 94 while(scanf("%d%d",&n,&m),n+m) 95 { 96 tp=0; 97 memset(head,-1,sizeof(head)); 98 for(int i=0;i<m;i++) 99 { 100 scanf("%d%d",&u,&v); 101 add_edge(u,v); 102 add_edge(v,u); 103 } 104 105 has_cut_vertex=false; 106 if(solve()) 107 printf("YES\n"); 108 else 109 printf("NO\n"); 110 } 111 return 0; 112 }
poj,3177
一開始是聯通圖,而後問加多少邊,使得整個圖變成雙聯通。
求出橋,刪除橋邊,得出的聯通塊爲雙聯通份量,收縮塊,而後求出獲得的樹加多少邊變成雙聯通圖,至少(lead+1)/2。
若是用臨接表建邊不須要考慮重邊問題;
若是用臨接矩陣建邊要考慮重邊問題:可是咱們能夠在建邊的時候不把重邊建進去,而後依舊用low來劃分雙聯通。
注意:low值相等說明在同一個雙聯通份量塊裏面,不等則度數加一,而後判斷葉子節點的個數最後求解。
1 #include <iostream> 2 #include <cstdlib> 3 #include <cstdio> 4 #include <cstring> 5 #include <algorithm> 6 7 #define maxn 5050 8 9 struct edge 10 { 11 int v,next; 12 }; 13 14 using namespace std; 15 edge E[10010]; 16 int head[maxn]; 17 int n,m,tp,t,ans; 18 int dfn[maxn],low[maxn]; 19 bool map[maxn][maxn]; 20 21 void add_edge(int u,int v) 22 { 23 E[tp].v=v; 24 E[tp].next=head[u]; 25 head[u]=tp++; 26 } 27 28 void Tarjan(int u,int p) 29 { 30 dfn[u]=low[u]=++t; 31 for(int i=head[u];i!=-1;i=E[i].next) 32 { 33 int v=E[i].v; 34 35 if(!dfn[v])//若是爲樹邊 36 { 37 Tarjan(v,u); 38 low[u]=min(low[u],low[v]); 39 } 40 else if(v!=p)//不走回頭路且爲後向邊 41 { 42 low[u]=min(low[u],dfn[v]); 43 } 44 } 45 46 } 47 48 void output() 49 { 50 int cnt[maxn],num=0; 51 memset(cnt,0,sizeof(cnt)); 52 53 for(int i=1;i<=n;i++) 54 for(int j=head[i];j!=-1;j=E[j].next) 55 { 56 int v=E[j].v; 57 if(low[v]!=low[i]) 58 cnt[low[i]]++; //求出每一個點的度,當成有向圖求。若是無向圖則最後判斷,度要除以2 59 } 60 61 for(int i=0;i<=n;i++) 62 if(cnt[i]==1) 63 num++; 64 printf("%d\n",(num+1)/2); 65 } 66 67 int main() 68 { 69 scanf("%d%d",&n,&m); 70 memset(head,-1,sizeof(head)); 71 memset(map,false,sizeof(map));//記錄重邊 72 memset(dfn,0,sizeof(dfn));//第一次訪問。 73 tp=t=0; 74 75 int a,b; 76 for(int i=0;i<m;i++) 77 { 78 scanf("%d%d",&a,&b); 79 if(!map[a][b]) 80 { 81 add_edge(a,b); 82 add_edge(b,a); 83 map[a][b]=map[b][a]=true; 84 } 85 } 86 Tarjan(1,1); 87 output(); 88 return 0; 89 }
uva,10765
一個鴿子把信息從最高指揮部帶出到一個station而後這個信息會被火車送往其餘未被轟炸的地方,求轟炸完一個station至少須要放多少隻鴿子把全部未轟炸的station都通知到。
一開始的想法就是:全部的點初始化鴿子數爲1,而後求出割點計算與之相連的聯通塊個數而後排序輸出題目要求的炸彈數就能夠了。
注意每一個station最多與另外10個station直接相連,因此建臨接表要注意區間= =😄
而後就是輸出格式。。。我真的見了你的鬼了。
1 #include <iostream> 2 #include <cstdlib> 3 #include <cstdio> 4 #include <cstring> 5 #include <algorithm> 6 7 #define maxn 10010 8 9 struct edge 10 { 11 int v,next; 12 }; 13 struct node 14 { 15 int cnt,u; 16 }; 17 18 19 using namespace std; 20 edge E[10*maxn+5];//注意最多有十條邊相連,對於每一個點/re了幾回😭 21 node G[maxn]; 22 int head[maxn]; 23 int n,m,tp,t,ans; 24 int dfn[maxn],low[maxn]; 25 26 void add_edge(int u,int v) 27 { 28 E[tp].v=v; 29 E[tp].next=head[u]; 30 head[u]=tp++; 31 } 32 33 bool cmp(node a,node b)//題目要求排序 34 { 35 if(a.cnt==b.cnt) return a.u<b.u; 36 return a.cnt>b.cnt; 37 } 38 void Tarjan(int u,int p)//求割點 39 { 40 dfn[u]=low[u]=++t; 41 42 int child=0; 43 for(int i=head[u];i!=-1;i=E[i].next) 44 { 45 int v=E[i].v; 46 if(v==p) continue; 47 if(!dfn[v]) 48 { 49 Tarjan(v,u); 50 child++; 51 low[u]=min(low[u],low[v]); 52 53 if((u==p && child>1) || (u!=p && low[v]>=dfn[u])) 54 G[u].cnt++;//把割點和與之相連的邊去掉以後能造成幾個聯通塊 55 } 56 else if(v!=p) 57 { 58 low[u]=min(low[u],dfn[v]); 59 } 60 } 61 62 } 63 64 void output() 65 { 66 sort(G,G+n,cmp);//打印輸出前m個數值 67 for(int i=0;i<m;i++) 68 printf("%d %d\n",G[i].u,G[i].cnt); 69 } 70 71 int main() 72 { 73 while(scanf("%d%d",&n,&m),n+m) 74 { 75 memset(head,-1,sizeof(head)); 76 memset(dfn,0,sizeof(dfn)); 77 memset(low,0,sizeof(low)); 78 for(int i=0;i<n;i++) 79 { 80 G[i].u=i; 81 G[i].cnt=1; 82 } 83 tp=t=0; 84 85 int a,b; 86 while(scanf("%d%d",&a,&b),(a+b)!=-2) 87 { 88 add_edge(a,b); 89 add_edge(b,a); 90 } 91 Tarjan(0,0); 92 output(); 93 printf("\n"); 94 } 95 return 0; 96 }