题目大意:有重边的无向图,问添加一条边最多能够减少多少个桥。
求出边-连通分量,缩点后得到一棵树。在该树中,所有的边都是桥,找LCA最远的两个叶子节点(就是树的直径),其所含的桥个数最多。因此连接该两个叶子节点可使得桥的个数减少最多。这是基本的算法思想。
然后的问题是如何处理重边?
”一般的简单无向图,tarjan求桥的dfs有两个参数x和fa,其中参数fa就是用于判定某边(x,t)是不是刚刚走过来的边.通常是用fa标记父节点。
在有重边的情形下,这样判就不太方便了。因为标记父节点之后就可能无法访问从fa出发的另一条重边了。
于是我们修改这个判定条件,把参数fa改为刚刚走过来的这条边的编号.
这就没问题了.至于具体的实现,由于一条无向边拆成两条有向边存下来的时候,编号是连续的,因此像类似4,5这样的两条边,可以通过判断4/2==5/2来判定是否是由同一条无向边拆出来的“
再一个就是如何求树的直径?相关证明
最后还有个问题:数据量很大。很容易爆栈。得加上这句
#pragma comment(linker,"/STACK:1024000000,1024000000")
然后用C++提交。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<vector> #include<stack> #include<queue> #pragma comment(linker,"/STACK:1024000000,1024000000") using namespace std; #define N 200005 struct Edge{ int v,next; }edge[2000010]; int pre[N],S[N],top,low[N],head[N],cnt,dfs_clock,bcc_cnt,bccno[N],bridge; inline void add(int u,int v){ edge[cnt].v=v; edge[cnt].next=head[u]; head[u]=cnt++; } void dfs(int u,int fa){ pre[u]=low[u]=++dfs_clock; S[top++]=u; for(int i=head[u];~i;i=edge[i].next){ if(i==(fa^1)) continue; int v=edge[i].v; if(!pre[v]){ dfs(v,i); low[u]=min(low[u],low[v]); } else if(!bccno[v]) low[u]=min(low[u],pre[v]); } if(low[u]==pre[u]){ ++bcc_cnt; for(;;){ int x=S[--top]; bccno[x]=bcc_cnt; if(x==u) break; } } } inline void find_bcc(int n){ memset(pre,0,sizeof(pre)); memset(bccno,0,sizeof(bccno)); dfs_clock=bcc_cnt=bridge=top=0; for(int i=0;i<n;++i) if(!pre[i]) dfs(i,-1); } vector<int>G[N]; int d[N]; bool vis[N]; queue<int>q; int bfs(int s,int &t){ memset(d,0,sizeof(d)); memset(vis,0,sizeof(vis)); t=s; int ans=0; q.push(s); vis[s]=1; while(!q.empty()){ int u=q.front(); q.pop(); for(int i=0;i<G[u].size();++i){ int v=G[u][i]; if(!vis[v]){ vis[v]=1; d[v]=d[u]+1; if(d[v]>ans){ ans=d[v]; t=v; } q.push(v); } } } return ans; } int main() { int i,j,n,m,x,y; while(~scanf("%d%d",&n,&m)&&(n+m)){ memset(head,-1,sizeof(head)); cnt=0; for(i=0;i<m;++i){ scanf("%d%d",&x,&y); add(--x,--y); add(y,x); } find_bcc(n); for(i=1;i<=bcc_cnt;++i) G[i].clear(); for(i=0;i<n;++i) for(j=head[i];~j;j=edge[j].next){ int v=edge[j].v; if(bccno[v]!=bccno[i]) G[bccno[i]].push_back(bccno[v]); } int p,ans=bfs(1,p); ans=max(ans,bfs(p,p)); printf("%d\n",bcc_cnt-1-ans); } return 0; }