hdu 3394 Railway
这是一道用tarjin求双连通分量的题;
其中,不需要修的道路就是桥的数目;
在图的每个极大环中,如果点的数目小于边的数目,显然这个环中含有子环,并且这个环的边数就是这个环中有冲突的边的数目;
如果点的数模等于边的数目,那就没有冲突;
代码:
1 #include<cstdio> 2 #include<vector> 3 #include<cstring> 4 using namespace std; 5 #define maxn 10005 6 7 vector<int>g[maxn]; 8 int block[maxn],top,stack[maxn],dfn[maxn],low[maxn],index,res1,res2; 9 bool instack[maxn],vis[maxn]; 10 11 void count_edge() 12 { 13 memset(vis,0,sizeof vis); 14 for(int i=1; i<=block[0]; i++) 15 vis[block[i]]=1; 16 int sum=0; 17 for(int i=1; i<=block[0]; i++) 18 { 19 int w=block[i]; 20 for(int j=0; j<g[w].size(); j++) 21 if(vis[g[w][j]]) 22 sum++; 23 } 24 sum/=2;//这个块中的边数 25 if(sum<block[0]) 26 res1+=sum; 27 if(sum>block[0]) 28 res2+=sum; 29 } 30 void tarjan(int v) 31 { 32 dfn[v]=low[v]=++index; 33 stack[++top]=v; 34 instack[v]=true; 35 for(int i=0; i<g[v].size(); i++) 36 { 37 int w=g[v][i]; 38 if(!dfn[w]) 39 { 40 tarjan(w); 41 low[v]=min(low[v],low[w]); 42 if(low[w]>=dfn[v]) 43 { 44 block[0]=0; 45 while(1) 46 { 47 block[++block[0]]=stack[top]; 48 instack[stack[top]]=0; 49 if(stack[top--]==w)break; 50 } 51 block[++block[0]]=v; 52 count_edge(); 53 } 54 } 55 else if(instack[w]) 56 low[v]=min(low[v],dfn[w]); 57 } 58 } 59 60 int main () 61 { 62 int n,m,x,y; 63 while(scanf("%d%d",&n,&m)==2 && n+m) 64 { 65 for(int i=0; i<n; i++)g[i].clear(); 66 for(int i=0; i<m; i++) 67 { 68 scanf("%d%d",&x,&y); 69 g[x].push_back(y); 70 g[y].push_back(x); 71 } 72 memset(dfn,0,sizeof dfn); 73 memset(low,0,sizeof low); 74 memset(instack,0,sizeof instack); 75 top=index=res1=res2=0; 76 for(int i=0; i<n; i++)if(!dfn[i])tarjan(i); 77 printf("%d %d\n",res1,res2); 78 } 79 return 0; 80 }