uva 10972(边双连通分量)

时间:2021-04-11 08:12:26

题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=33804

思路:和poj的一道题有点像,不过这道题图可能不连通,因此首先求边双连通分量,然后算每个连通分量的度数,显然叶子节点的度数为1,孤立点的度数为0,然后就是统计度数了,对于孤立点ans+=2,对于叶子节点,ans++。于是最后的答案就是(ans+1)/2了。

 #include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <stack>
#include <vector>
using namespace std;
#define MAXN 1111 int n, m, cnt, _count;
stack <int >S;
vector <vector<int > >g; int low[MAXN], dfn[MAXN], color[MAXN];
int degree[MAXN];
bool mark[MAXN];
void Tarjan(int u, int father)
{
low[u] = dfn[u] = ++ cnt;
S.push(u);
mark[u] = true;
for(int i = ; i < g[u].size(); i ++ ){
int v = g[u][i];
if(v == father)continue;
if(dfn[v] == ) {
Tarjan(v, u);
low[u] = min(low[u], low[v]);
} else if(mark[v]) {
low[u] = min(low[u], dfn[v]);
}
}
if(low[u] == dfn[u]){
int x;
_count++;
do {
x = S.top();
S.pop();
mark[x] = false;
color[x] = _count;
}while(x != u);
}
} int main()
{
int u, v, ans;
while(~scanf("%d %d", &n, &m)){
g.clear();
g.resize(n+);
while(m --){
scanf("%d %d",&u, &v);
g[u].push_back(v);
g[v].push_back(u);
}
memset(dfn, , sizeof(dfn));
memset(mark, false, sizeof(mark));
cnt = _count = ;
for(int i = ; i <= n; i ++){
if(dfn[i] == )Tarjan(i, -);
}
if(_count == ){
puts("");
continue;
}
memset(degree, , sizeof(degree));
for(int i = ; i <= n; i++){
for(int j = ; j < g[i].size(); j++){
if(color[i] != color[g[i][j]])degree[color[g[i][j]]] ++;
}
}
ans = ;
for(int i = ; i <= _count; i++){
if(degree[i] == )ans += ; // 孤立点
else if(degree[i] == )ans ++; // 叶子节点
}
printf("%d\n", (ans + )/ );
}
return ;
}