您的位置:首页 > 其它

POJ3177 && POJ3352_加最好的边构成双连通图

2012-08-16 08:40 295 查看
/*
*State: POJ3177    Accepted    340K    16MS    C++    1877B
*题目大意:
*        给出一个无向连通图,判断最少需要加多少条边,才能使得
*        任意两点之间至少有两条相互"边独立"的道路.注意,可能
*        含有重边.
*解题思路:
*        先缩点,之后形成一棵树,然后求(叶子节点数量+1)/ 2即可。
*/


View Code

#include <iostream>
#include <vector>
#include <stack>
using namespace std;

const int MAXN = 1005;

vector<int> vec[MAXN];
stack<int> S;
int dfn[MAXN], low[MAXN], step;
int id[MAXN], scc;

void init()
{
while(!S.empty())
S.pop();

step = 0;
scc = 1;
for(int i = 0; i < MAXN; i++)
{
id[i] = -1;
vec[i].clear();
dfn[i] = low[i] = -1;
}
}

void addEdge(int u, int v)
{
vec[u].push_back(v);
vec[v].push_back(u);
}

void tarjan_scc(int n, int father)
{
dfn
= low
= ++step;
S.push(n);
int flag = 0;
for(unsigned i = 0; i < vec
.size(); i++)
{
int son = vec
[i];
if(son == father && !flag)
{
flag = 1;
continue;
}

if(dfn[son] == -1)
{
tarjan_scc(son, n);
low
= min(low
, low[son]);
}
else
low
= min(low
, dfn[son]);
}

if(low
== dfn
)
{
int tmp;
do
{
tmp = S.top();
id[tmp] = scc;
//    cout << tmp << " ";
S.pop();
}while(!S.empty() && tmp != n);
scc++;
//cout << endl << "---------------" << endl;
}
}

void deal_scc(int n, int &sol)
{
int u, v;
int du[MAXN] = {0};
for(int i = 1; i <= n; i++)
{
for(unsigned j = 0; j < vec[i].size(); j++)
{
u = i, v = vec[i][j];
if(id[u] == id[v])
continue;
else
{
du[id[v]]++; du[id[u]]++;
}
}
}
int sum = 0;
for(int i = 1; i < scc; i++)
{
if(du[i] == 2)
sum++;
}
sum++;
sol = sum / 2;
}

int main(void)
{
#ifndef ONLINE_JUDGE
freopen("in3352.txt", "r", stdin);
#endif

int n, m;
while(scanf("%d %d", &n, &m) == 2)
{
init();
int u, v;
for(int i = 0; i < m; i++)
{
scanf("%d %d", &u, &v);
addEdge(u, v);
}
tarjan_scc(1, 1);
int sol;
deal_scc(n, sol);
printf("%d\n", sol);
//cout << "****************" << endl;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐