给定一个图,要求你添加一个边,使这个图的桥最少。
我几乎是蒙蔽的。
先缩个点,然后求一遍树的直径。
然后用 原先的桥数 减去树的直径就好了。
或者 用强连通分量树 -1-树的直径
(缩点后一个scc就是一个点,而桥就是边,并且是树,如果不是树就缩点缩了)
发现了吧。有的人把剩下的桥 叫做 枝叶边, 就是那个红点那个边
就是要求的 剩下的最小的桥数
(要求添加的那个一边,从直径头到尾,把所有直径边想当桥的愿望都给否定了)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <bits/stdc++.h>
/*先缩点,变成一个树,然后再求树的直径,然后那个
原来的桥数减去直径 在减1(因为还要在添)
*/
using namespace std;
const int maxm=1000008;
const int maxn=200005;
struct Node
{ int to,next,cost;
}node[maxm*2];
int len;
int head[maxn];
void add(int u,int v){
node[len].to=v;
node[len].next=head[u];
//node[len].cost=w;
head[u]=len++;
}
int low[maxn];
int dfn[maxn];
int cnt[maxn];
int num[maxn];
int index;
int bridge;
int scc;
vector<int>G[maxn];
stack<int>s;
int m,n,a,b;
void init(){
index=0;
len=0;
scc=0;
bridge=0;
memset(head,-1,sizeof(head));//链表
memset(num,0,sizeof(num));//各scc多少个
memset(dfn,0,sizeof(dfn));//
memset(low,0,sizeof(low));
for(int i=0;i<maxn;i++)
G[i].clear();
while(!s.empty())
s.pop();
}
void tarjan(int m,int pre){
low[m]=dfn[m]=++index;
s.push(m);
for(int i=head[m];i!=-1;i=node[i].next)
{
if(i==(pre^1))continue;
int v=node[i].to;
if(!dfn[v])
{
tarjan(v,i);
if(low[v]<low[m])
low[m]=low[v];
if(low[v]>dfn[m])//这就是 桥的条件
bridge++;
}else if(dfn[v]<low[m])//下一个点的dfs顺序比他能到达的小,就换
low[m]=dfn[v];
}
if(low[m]==dfn[m])
{
scc++;
for(;;)
{
int x = s.top();s.pop();
cnt[x]=scc;
num[scc]++;
if(x==m)break;
}
}
}
int dis[maxn];
bool vis[maxn];
int dfs(int a){
for(int i=0;i<G[a].size();i++){
int v=G[a][i];
if(!vis[v])
{vis[v]=true;
dis[v]=dis[a]+1;
dfs(v);
}
}
}
void solve(){
memset(dis,0,sizeof(dis));
memset(vis,false,sizeof(vis));
vis[1]=true;
dis[1]=0;
dfs(1);
int dex=1;
int sum=-1;
for(int i=1;i<=scc;i++){
if(dis[i]>sum)
{sum=dis[i];//
dex=i;
}
}
memset(dis,0,sizeof(dis));
memset(vis,false,sizeof(vis));
vis[dex]=true;
dis[dex]=0;
dfs(dex);
sum=-1;
dex=1;
for(int i=1;i<=scc;i++){
if(dis[i]>sum)
sum=dis[i];
}
// cout<<bridge<<endl;
//cout<<sum<<endl;
//printf("%d\n",bridge-sum);
printf("%d\n",scc-1-sum);
}
int main()
{ while(~scanf("%d%d",&m,&n)){
if(m==0||n==0) break;
init();
for(int i=1;i<=n;i++){
scanf("%d%d",&a,&b);
add(a,b);
add(b,a);
}
for(int i=1;i<=m;i++)
if(!dfn[i])
tarjan(i,-1);
for(int i=1;i<=m;i++){
for(int j=head[i];j!=-1;j=node[j].next)
{ int v=node[j].to;
if(cnt[v]==cnt[i]) continue;
G[cnt[v]].push_back(cnt[i]);
G[cnt[i]].push_back(cnt[v]);//缩点
}
}
solve();
}
return 0;
}