您的位置:首页 > 其它

POJ 3352 Road Construction (边双连通,缩点)

2011-10-22 10:29 323 查看
题意:加上最少的边,使得改造后的图中去掉任意一条边后图依然连通。

题解:先找出边双连通分量,然后缩点,的到一棵树。需要加的最少边=(leaves+1)/2

PS:



我们可以发现low[4]=3,low[7]=4 但是我们知道<4,7>这条边并不是割边.所以 low[u]!=low[v]是割边的必要不充分条件.

 

#include<cstdio>
#include<string>
#include<algorithm>
using namespace std;
#define N 2009
int n, m, leaves;
int size, scc, id, top;
int stack
, instack
;
int head
, low
, dfn
, degree
, block
;
struct Edge { int v, next; } edge[N*3];

void Tarjan ( int u, int father )
{
int v, t;
stack[++top] = u;
instack[u] = 1;
dfn[u] = low[u] = ++id;
for ( int i = head[u]; i; i = edge[i].next )
{
v = edge[i].v;
if ( father == v ) continue;
if ( ! dfn[v] )
{
Tarjan ( v, u );
low[u] = min ( low[u], low[v] );
if ( dfn[u] < low[v] )
{
scc++;
do
{
t = stack[top--];
instack[t] = 0;
block[t] = scc;
} while ( v != t );
}
}
else if ( instack[v] )
low[u] = min ( low[u], dfn[v] );
}
}

void shrink()
{
int u, v, i;
for ( u = 1; u <= n; u++ )
{
for ( i = head[u]; i; i = edge[i].next )
{
v = edge[i].v;
if ( block[u] != block[v] )
{
degree[block[u]]++;
degree[block[v]]++;
}
}
}
for ( i = 1; i <= scc; i++ ) //由于每个点重复计算了一次,所以叶子节点的度为2
if ( degree[i] == 2 ) leaves++;
}

void Initial()
{
size = id = scc = top = leaves = 0;
for ( int i = 1; i <= n; i++ )
{
head[i] = degree[i] = instack[i] = 0;
low[i] = dfn[i] = block[i] = 0;
}
}

void add ( int u, int v )
{
size++;
edge[size].v = v;
edge[size].next = head[u];
head[u] = size;
}

int main()
{
int u, v;
while ( scanf("%d%d",&n,&m) != EOF )
{
Initial();
while ( m-- )
{
scanf("%d%d",&u,&v);
add ( u, v );
add ( v, u );
}
for ( int i = 1; i <= n; i++ )
if ( ! dfn[i] ) Tarjan ( i, n+1 );

shrink();
printf("%d\n",(leaves+1)/2 );
}
return 0;
}


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