Problem Description
输入n,m代表有n个点,有m条边。有重边,这里重边指的是1-2,1-2如果出现了两次,代表1-2有两条不同的道路接下面m行,每行u,v代表u-v有一条道路(双向)。问你加一条边,最少还剩下多少个桥
思路:
树的直径参考:http://blog.csdn.net/Triple_WDF/article/details/50118115 将图按双连通分量缩点后,桥的数量-直径的长度 就是结果。
有重边所以得特殊处理下,1-2,2-1如果是同一条边,那么1到2后 2不能到1。如果不是同一条边1-2后,2可以到1。所以求双连通分量的时候判断一下是不是同一条边就可以了
#include<bits/stdc++.h>
using namespace std;
#define mm 1000055
#define nn 200055
struct node
{
int to, next;
};
node Map[2 * mm];//前向星存图
int head[nn], low[nn], dfn[nn], vis[nn], top, sig, N, Stack[nn];
//vis[i]代表i属于vis[i]这个双连通分量
int n, vv[nn], d, flag;
node MAP[mm];
int cc;
void add(int u, int v, int &cnt)//相邻的cnt奇偶是同一条边,例如0,1是同一条边 奇数^1 为偶数(奇数-1) 偶数^1 为 奇数(偶数+1).所以相当于同一条边
{
Map[cnt].to = v;
Map[cnt].next = head[u];
head[u] = cnt++;
}
void tardfs(int u, int father)
{
low[u] = dfn[u] = sig++;
Stack[top++] = u;
for(int i = head[u]; ~i; i = Map[i].next)
{
int to = Map[i].to;
if(!dfn[to])
{
tardfs(to, i);
low[u] = min(low[u], low[to]);
if(low[to] > dfn[u])//记录割边两端的的点
{
MAP[cc].to = u;
MAP[cc++].next = to;
}
}
else if(!vis[to] && i != (father ^ 1))//不是同一条边
{
low[u] = min(low[u], dfn[to]);
}
}
if(low[u] == dfn[u])//缩点
{
N++;
do
{
int t = Stack[top - 1];
vis[t] = N;
top--;
}while(Stack[top] != u);
}
}
void tarjan()
{
top = 0, sig = 1, N = 0;
memset(vis, 0, sizeof(vis));//初始化
memset(dfn, 0, sizeof(dfn));
for(int i = 1; i <= n; i++)
{
if(!vis[i]) tardfs(i, i);
}
}
void dfs(int u)
{
for(int i = head[u]; ~i; i = Map[i].next)
{
int to = Map[i].to;
if(!vv[to]) {
vv[to] = vv[u] + 1;
if(vv[to] > d)
{
d = vv[to];
flag = to;
}
dfs(to);
}
}
}
int main()
{
int m, u, v;
while(~scanf("%d %d", &n, &m))
{
if(!n && !m) break;
int cnt = 0;//初始化
memset(head, -1, sizeof(head));
while(m--)
{
scanf("%d %d", &u, &v);
add(u, v, cnt);//双向
add(v, u, cnt);
}
cc = 0;
tarjan();//缩点,求双连通分量
cnt = 0;
memset(head, -1, sizeof(head));
for(int i = 0; i < cc; i++)//按照缩点后,建图
{
u = MAP[i].to, v = MAP[i].next;
if(vis[u] != vis[v]) {
add(vis[u], vis[v], cnt);
add(vis[v], vis[u], cnt);
}
}
memset(vv, 0, sizeof(vv));//两次dfs求树的直径
vv[1] = 1;
d = 1;
flag = 1;
dfs(1);
memset(vv, 0, sizeof(vv));
vv[flag] = 1;
d = 1;
dfs(flag);
printf("%d\n", cc - d + 1);
}
}