poj 3353 Road Construction tarjan 边双联通分支 缩点+结论

题意:一个连通的无向图,求至少需要添加几条边,救能保证删除任意一条边,图仍然是连通的。

链接:http://poj.org/problem?id=3352

思路:边的双连通图。其实就是要求至少添加几条边,可以使整个图成为一个边双连通图。用tarjan算法(求割点割边)求出low数组,这里可以简化,然 后依据“low相同的点在一个边连通分量中”,缩点之后构造成树(这里可以直接利用low[]数组,low[i]即为第i节点所在的连通分量的标号)。求 出树中出度为1的节点数left,答案即为(leaf+1)/2。

代码:

 #include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <stdlib.h>
#include <vector>
#include <queue>
#include <stack>
#define loop(s,i,n) for(i = s;i < n;i++)
#define cl(a,b) memset(a,b,sizeof(a))
const int maxn = ;
using namespace std;
int dfn[maxn],low[maxn],belong[maxn],dfsclock,bcc_cnt;
vector<int>g[maxn];
vector<int>ng[maxn];
struct edge
{
int u,v,w;
};
stack<edge> st;
vector<edge> edges;
stack<int>s;
void init(int n)
{
int i;
for(i = ; i <= n; i++)
g[i].clear();
edges.clear();
return ;
}
int in[maxn];
void tarjan(int u,int pre)
{
int v,i,j;
dfn[u] = low[u] = ++dfsclock;
s.push(u);
loop(,i,g[u].size())
{
v = g[u][i]; if(v != pre)
{
if(!dfn[v])//保证是树枝边
{
tarjan(v,u); low[u] = min(low[v],low[u]); }
else if(dfn[v] < low[u])
low[u] = dfn[v];
} }
if(low[u] ==dfn[u])
{
bcc_cnt++;
int t;
do
{ t = s.top();
s.pop();
belong[t] = bcc_cnt;
}
while(t != u);
}
} void find_bcc(int n)
{
int i;
memset(dfn,,sizeof(dfn));
memset(low,,sizeof(low)); memset(belong,,sizeof(belong));
while(!s.empty())s.pop();
dfsclock = bcc_cnt = ;
loop(,i,n)
if(!dfn[i]) tarjan(i,-);
// puts("yes");
// printf("%d """"""\n",bcc_cnt);
} int main()
{
int m,n; while(~scanf("%d %d",&n,&m))
{
init(n);
int i,j;
for(i = ; i <= m; i++)
{
int u,v;
struct edge e;
scanf("%d %d",&u,&v);
g[u].push_back(v);
g[v].push_back(u);
e.u = u;
e.v = v;
edges.push_back(e);
} find_bcc(n);
cl(in,);
struct edge e;
for(j = ; j < edges.size(); j++)
{
e = edges[j];
if(belong[e.v] != belong[e.u])
{
in[belong[e.v]]++;
in[belong[e.u]]++;
}
}
int leaf;
leaf = ;
// cout<<bcc_cnt<<endl;
for(i = ; i <= bcc_cnt; i++)
if(in[i]==)
leaf++; cout<<(leaf+)/<<endl;
}
return ;
}
上一篇:python 正则基本方法


下一篇:jQuery函数学习