pku 3694 Network tarjan求割邊


http://poj.org/problem?id=3694

給你一個存在橋的無向連通圖,每次增加一條邊,問每次增加邊之后還剩多少個橋。

朴素的辦法就是每輸入一次tarjan求一次橋的個數,肯定會tle;

正確的做發是,首先求出改圖的橋的數量,在tarjan的過程中里用並查集把不是橋的邊縮為一點,然后得到一棵樹,每加入一條邊,就肯定會形成一個環,,然后刪除環中石橋的邊,最后得出總的橋的數量。刪除的過程就是檢查是否石橋是就有cut--;

View Code
#include <cstdio>
#include <cstring>
#include <vector>
#include <iostream>
#define maxn 100010
using namespace std;
int low[maxn],dfn[maxn],father[maxn],f[maxn];
int index,n,m,q,cut;
vector<int>g[maxn];
void init(int nn)
{
for (int i = 0; i <= n+1; ++i)
{
g[i].clear();
low[i] = dfn[i] = father[i] = 0;
f[i] = i;
}
index = cut = 0;
}
int find(int x)
{
if (f[x] != x)
f[x] = find(f[x]);
return f[x];
}
int Union(int x,int y)
{
x = find(x);
y = find(y);
if (x != y)
{
f[y] = x;
return 1;
}
else
return 0;

}
void tarjan(int i,int pre)
{
int j,k;
low[i] = dfn[i] = ++index;
for (k = 0; k < g[i].size(); ++k)
{
j = g[i][k];
if (!dfn[j])
{
tarjan(j,i);
low[i] = min(low[i],low[j]);
father[j] = i;//記錄每個節點的父親,方便后面的環中的查找
if (low[j] > dfn[i])//記錄橋數
cut++;
else
Union(i,j);//把不是橋的縮為一點
}
else if (j != pre)//這里要注意不能是i的父親,反之low[i] = low[father[i]]了;
{
low[i] = min(low[i],dfn[j]);
}
}
}
void lca(int u,int v)
{
//在環中找橋的過程
while (u != v)
{
while (dfn[u] >= dfn[v] && u != v)
{
if (Union(u,father[u]))
cut--;
u = father[u];
}
while (dfn[v] >= dfn[u] && u != v)
{
if (Union(v,father[v]))
cut--;
v = father[v];
}
}
}
int main()
{
//freopen("d.txt","r",stdin);
int i,x,y,cas = 1;
while (scanf("%d%d",&n,&m))
{
if (!n && !m) break;
printf("Case %d:\n",cas++);
init(n);
for (i = 0; i < m; ++i)
{
scanf("%d%d",&x,&y);
g[x].push_back(y);
g[y].push_back(x);
}
/*for (i = 1; i <= n; ++i)
{
for (int j = 0; j < g[i].size(); ++j)
printf("%d ",g[i][j]);
puts(" ");
}
*/
tarjan(1,-1);
//printf(">>>%d\n",cut);
cin>>q;
while (q--)
{
cin>>x>>y;
lca(x,y);
printf("%d\n",cut);
}
printf("\n");
}
return 0;
}




注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
  © 2014-2022 ITdaan.com