标签:
4 4 1 2 1 3 1 4 2 3 0 0
0
题意:有N个点,M条边,加一条边,求割边最少(有重边,所有点在原图中都是连通的)。
割边:在原图中去掉该边,原图变得不连通,这样的边成为割边。
思路:先求无向图的连通分量,缩点形成一个生成树,可知树中所有边都为割边,采用贪
心的策略可知,再加一条边,最少的割边数为 ans = 所有割边数 - 数的直径 。
因为有的图上可能有重边,这样不好处理。我们记录每条边的标号(一条无向边拆成的两
条有向边标号相同)这样就能限制不走一样的边而能走重边!
#pragma comment(linker, "/STACK:1024000000,1024000000") #include <iostream> #include <algorithm> #include <cstdio> #include <cstring> #include <vector> #include <stack> using namespace std; const int maxn=200010; struct edge { int u,v; edge() {} edge(int uu,int vv):u(uu),v(vv) {} } a[maxn*10]; int n,m,dfs_clock,cnt,index,id[maxn],S[maxn],low[maxn],dfn[maxn],belong[maxn],num[maxn]; vector <int> G[maxn],T[maxn]; stack <int> st; bool mark[maxn],visited[maxn*10]; void initial() { memset(low,0,sizeof(low)); memset(dfn,0,sizeof(dfn)); memset(num,0,sizeof(num)); memset(mark,0,sizeof(mark)); memset(belong,0,sizeof(belong)); memset(visited,0,sizeof(visited)); for(int i=0; i<maxn; i++) { T[i].clear(); G[i].clear(); } while(!st.empty()) st.pop(); index=0; dfs_clock=1; cnt=0; } void input() { int u,v; for(int i=0; i<m; i++) { scanf("%d %d",&u,&v); G[u].push_back(cnt); a[cnt++]=edge(u,v); G[v].push_back(cnt); a[cnt++]=edge(v,u); } } void tarjan(int u,int fa) { dfn[u]=low[u]=dfs_clock++; st.push(u); mark[u]=1; for(int i=0; i<G[u].size(); i++) { int tp=G[u][i]; if(visited[tp]) continue; visited[tp]=visited[tp^1]=1; int v=a[tp].v; if(!dfn[v]) { tarjan(v,tp); low[u]=min(low[v],low[u]); } else if(mark[v]) low[u]=min(low[u],dfn[v]); } if(low[u]==dfn[u]) { index++; while(1) { int t=st.top(); st.pop(); belong[t]=index; if(t==u) break; } } } void solve1() { for(int i=1; i<=n; i++) if(!dfn[i]) tarjan(i,-1); for(int i=0; i<cnt; i+=2) { int p=belong[a[i].u],q=belong[a[i].v]; if(p!=q) { T[p].push_back(q); T[q].push_back(p); } } } void dfs(int u,int v,int depth) { num[v]=depth; for(int i=0; i<T[v].size(); i++) { int vv=T[v][i]; if(vv==u) continue; dfs(v,vv,depth+1); } } void solve2() { int Max=-1,k=-1; dfs(-1,1,0); for(int i=1; i<=index; i++) if(Max<num[i]) Max=num[i],k=i; memset(num,0,sizeof(num)); dfs(-1,k,0); for(int i=1; i<=index; i++) Max=max(Max,num[i]); printf("%d\n",index-1-Max); } int main() { while(scanf("%d %d",&n,&m)!=EOF) { if(n==0 && m==0) break; initial(); input(); solve1(); solve2(); } return 0; }
hdu 4612 Warm up (带有重边的无向图Tarjan+树的直径)
标签:
原文地址:http://blog.csdn.net/u012596172/article/details/43085777