標籤:
大意:給定n點,和m條邊的關係圖中的一些邊隨時可能施工導致不能夠通過,所以至少加多少條邊才能夠使得途中任意兩條邊聯通?
思路:很明顯只要圖中的任意兩點都是兩條邊來連結即可。那麼我們可以先縮點構建新圖,然後統計出度為1的點的個數ans,那麼需要加的邊數就是(ans+1)/2條;
(PS;因為建圖是雙向的圖所以,在Tarjan縮點的時候就需要遇到臨邊便越過,並且判斷是不是同一個聯通分支用num比較!)
#include<map>#include<queue>#include<cmath>#include<cstdio>#include<stack>#include<iostream>#include<cstring>#include<algorithm>#define LL int#define inf 0x3f3f3f3f#define eps 1e-8#include<vector>#define ls l,mid,rt<<1#define rs mid+1,r,rt<<1|1using namespace std;int n,m;const int Ma = 1000005;int head[Ma],dfn[Ma],num[Ma],du[Ma],stk[Ma],vis[Ma],low[Ma];int cnt,top,time,css;bool mp[5100][5100];struct node{ int to,next;}q[Ma];void bu(int a,int b){ q[cnt].to = b; q[cnt].next = head[a]; head[a] = cnt++;}void init(){ time = 1; css = top = cnt = 0; memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(vis,0,sizeof(vis)); memset(head,-1,sizeof(head)); memset(num,0,sizeof(num)); memset(du,0,sizeof(du)); memset(mp,false,sizeof(mp));}void Tarjan(int u,int To){ low[u] = dfn[u] = time++; vis[u] = 1; stk[top++] = u; for(int i = head[u]; ~i ; i = q[i].next){ int v = q[i].to; if(i == (To^1)) continue; if(!vis[v]){ Tarjan(v,i); low[u] = min(low[u],low[v]); } else low[u] = min(low[u],dfn[v]); } if(low[u] == dfn[u]){//找到極大聯通分量 css++; while(top > 0&&stk[top] != u){ top --; vis[stk[top] ] = 2; num[stk[top] ] = css; } }}int main(){ int k,i,j,a,b; while(~scanf("%d%d",&n,&m)){ init(); for(i = 0;i < m;++ i){ scanf("%d%d",&a,&b);//////注意重邊的問題! if(mp[a][b]){ continue; } mp[a][b] = mp[b][a] = true; bu(a,b); bu(b,a); } Tarjan(1,-1); for(i = 1;i <= n;++ i) for(j = head[i]; ~j ;j = q[j].next) if( num[i] != num[q[j].to] ) du[num[i] ]++; int ans = 0; for(i = 1;i <= n;++ i) if(du[i] == 1) ans++; printf("%d\n",(ans+1)>>1); } return 0;}
POJ 3352 Road Construction&& POJ 3177 Redundant Paths 雙聯通分量