大意:给定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|1 using 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; }
时间: 2024-10-09 15:22:01