题意:
给出n个点和m条边的无向图,存在重边,问加一条边以后,剩下的桥的数量最少为多少。
题解:
把这个无向图缩点后会得到一个只由桥来连接的图(可以说这个图中的所有边都是桥,相当于一棵树),
然后我们只需要找出来这棵树的最大直径(即相距最远的两个点)。
因为如果我们把直径所在的两个端点连起来,这样减少的桥最多。
所以 答案就是 桥的数量 - 树的直径上桥的数量
原图求桥的数量,缩点后建立新的图求直径
代码:

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <map>
#include <queue>
using namespace std;
const int maxn = 200005;//点数
const int maxm = 2001000;//边数,因为是无向图,所以这个值要*2
struct Edge
{
int to,next;
bool cut;//是否是桥标记
} edge[maxm],edge1[maxm];
int head[maxn],tot,head1[maxn],tot1;
int low[maxn],dfn[maxn],Stack[maxn],belong[maxn];//belong数组的值是1~scc
int Index,top;
int scc;//边双连通块数/强连通分量的个数
bool Instack[maxn];
int bridge;//桥的数目
bool cut[maxn];
void addedge(int u,int v)
{
edge[tot].to = v;
edge[tot].next = head[u];
edge[tot].cut=false;
head[u] = tot++;
}
void add(int u,int v)
{
edge1[tot1].to = v;
edge1[tot1].next = head1[u];
head1[u] = tot1++;
}
void Tarjan(int u,int pre)
{
int v;
low[u] = dfn[u] = ++Index;
Stack[top++] = u;
Instack[u] = true;
int son=0;
int flag=0;
for(int i = head[u]; i != -1; i = edge[i].next)
{
v = edge[i].to;
if(v == pre && !flag)
{
flag++;
continue;
}
if( !dfn[v] )
{
son++;
Tarjan(v,u);
if( low[u] > low[v] )low[u] = low[v];
if(low[v] > dfn[u])
{
bridge++;
edge[i].cut = true;
edge[i^1].cut = true;
}
if(u == pre && son > 1)cut[u] = true;
if(u != pre && low[v] >= dfn[u])cut[u] = true;
}
else if( Instack[v] && low[u] > dfn[v] )
low[u] = dfn[v];
}
if(low[u] == dfn[u])
{
scc++;
do
{
v = Stack[--top];
Instack[v] = false;
belong[v] = scc;
}
while( v!=u );
}
}
void init()
{
tot = 0;
memset(head,-1,sizeof(head));
}
void init1()
{
tot1 = 0;
memset(head1,-1,sizeof(head1));
}
int deep[maxn];
int bfs(int s)
{
queue<int> Q;
memset(deep,0,sizeof deep);
deep[s] = 1;
Q.push(s);
int ans = s;
while(!Q.empty())
{
int u = ans = Q.front();
Q.pop();
for(int i=head1[u]; ~i; i=edge1[i].next)if(!deep[edge1[i].to])
{
int v=edge1[i].to;
deep[v] = deep[u]+1;
Q.push(v);
}
}
return ans;
}
void solve(int n)
{
memset(dfn,0,sizeof(dfn));
memset(Instack,false,sizeof(Instack));
memset(cut,0,sizeof cut);
Index = top = scc = 0;
bridge = 0;
for(int i = 1; i <= n; i++)
if(!dfn[i])
Tarjan(i,i);
init1();
for(int i=1; i<=n; i++)
{
for(int j=head[i]; ~j; j=edge[j].next)
{
int u=belong[i];
int v=belong[edge[j].to];
if(u!=v)
{
add(u,v);
add(v,u);
}
}
}
int ans=deep[bfs(bfs(1))];
printf("%d\n",scc-1-(ans-1));
}
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m) && (n || m))
{
init();
while(m--)
{
int u,v;
scanf("%d%d",&u,&v);
addedge(u,v);
addedge(v,u);
}
solve(n);
}
return 0;
}
/*
4 4
1 2
1 3
1 4
2 3
0 0
*/
