您的位置:首页 > 其它

HDU 4612 Warm up(边双连通分量)

2016-02-05 20:27 330 查看
题意:n个顶点,m条边(有重边),问增加一条边,使原来桥边减少最多

思路:求出图中的边双连通分量,缩点建新图,然后求出这颗树的直径,新加的边应该在直径的两边,这样才能使原图中桥最小。因为重边的原因,在dfs的时候,对于从u到v,在v也一定会有一条路径到u,加一个变量标记一下就可以了。 求树的直径的做法:随便找一个点找与它距离最远的点,然后从这个点出发再做一次,就是树的直径了

#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
#include<stack>
using namespace std;
const int maxn=200010+10;
const int INF = 100000000;
int ans;
int n,m;
int dfs_clock;//时钟,每访问一个节点增1
vector<int> G[maxn];//G[i]表示i节点邻接的所有节点
int pre[maxn];//pre[i]表示i节点被第一次访问到的时间戳,若pre[i]==0表示i还未被访问
int low[maxn];//low[i]表示i节点及其后代能通过反向边连回的最早的祖先的pre值
vector<int>NewG[maxn];
bool vis[maxn];
int dis[maxn];
int sccno[maxn];
int scc_cnt;
stack <int>S;
int p;
int bridge;
//求出以u为根节点(u在DFS树中的父节点是fa)的树的所有割顶和桥
//初始调用为dfs(root,-1);
void dfs(int u,int fa)
{
int flag = 0;
pre[u]=low[u]=++dfs_clock;
S.push(u);
for (int i = 0;i<G[u].size();i++)
{
int v = G[u][i];
if (v==fa && !flag)
{
flag++;
continue;
}
if (!pre[v])
{
dfs(v,u);
low[u]=min(low[u],low[v]);
if (low[v]>pre[u])
bridge++;
}
else
low[u]=min(low[u],pre[v]);
}
if (low[u]==pre[u])
{
scc_cnt++;
for (;;)
{
int x = S.top();
S.pop();
sccno[x]=scc_cnt;

if (x==u)
break;
}
}
}
void bfs(int s)
{
memset(vis,0,sizeof(vis));
memset(dis,0,sizeof(dis));
queue<int>q;
q.push(s);
vis[s]=1;
while (!q.empty())
{
int u = q.front();
q.pop();
for (int i = 0;i<NewG[u].size();i++)
{
int v = NewG[u][i];
if (vis[v])
continue;
vis[v]=1;
dis[v]=dis[u]+1;
if (ans < dis[v])
{
p=v;
ans = dis[v];
}
q.push(v);
}
}
}
void find_scc()
{
dfs_clock=scc_cnt=bridge=0;
memset(sccno,0,sizeof(sccno));
memset(pre,0,sizeof(pre));
for (int i = 1;i<=n;i++)
if (!pre[i])
dfs(i,-1);
}
int main()
{
while(scanf("%d%d",&n,&m)==2&&n)
{
for(int i=0;i<=n;i++) G[i].clear(),NewG[i].clear();
for(int i=0;i<m;i++)
{
int u,v,w;
scanf("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
find_scc();
for (int u=1;u<=n;u++)
{
for (int i = 0;i<G[u].size();i++)
{
int v = G[u][i];
if (sccno[u]!=sccno[v])
{
NewG[sccno[u]].push_back(sccno[v]);
NewG[sccno[v]].push_back(sccno[u]);
}
}
}
ans=0;
bfs(1);
bfs(p);
printf("%d\n",bridge-ans);
}
return 0;
}


Description

  N planets are connected by M bidirectional channels that allow instant transportation. It's always possible to travel between any two planets through these channels.

  If we can isolate some planets from others by breaking only one channel , the channel is called a bridge of the transportation system.

People don't like to be isolated. So they ask what's the minimal number of bridges they can have if they decide to build a new channel.

  Note that there could be more than one channel between two planets.

Input

  The input contains multiple cases.

  Each case starts with two positive integers N and M , indicating the number of planets and the number of channels.

  (2<=N<=200000, 1<=M<=1000000)

  Next M lines each contains two positive integers A and B, indicating a channel between planet A and B in the system. Planets are numbered by 1..N.

  A line with two integers '0' terminates the input.

Output

  For each case, output the minimal number of bridges after building a new channel in a line.

Sample Input

4 4
1 2
1 3
1 4
2 3
00


Sample Output

0
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: