题目大意:有重边的无向图,问添加一条边最多能够减少多少个桥。
求出边-连通分量,缩点后得到一棵树。在该树中,所有的边都是桥,找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;
}
#pragma comment(linker,"/STACK:1024000000,1024000000")