题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=33804、
思路:和poj的一道题有点像,不过这道题图可能不连通,因此首先求边双连通分量,然后算每个连通分量的度数,显然叶子节点的度数为1,孤立点的度数为0,然后就是统计度数了,对于孤立点ans+=2,对于叶子节点,ans++。于是最后的答案就是(ans+1)/2了。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <stack> 6 #include <vector> 7 using namespace std; 8 #define MAXN 1111 9 10 int n, m, cnt, _count; 11 stack <int >S; 12 vector <vector<int > >g; 13 14 int low[MAXN], dfn[MAXN], color[MAXN]; 15 int degree[MAXN]; 16 bool mark[MAXN]; 17 void Tarjan(int u, int father) 18 { 19 low[u] = dfn[u] = ++ cnt; 20 S.push(u); 21 mark[u] = true; 22 for(int i = 0; i < g[u].size(); i ++ ){ 23 int v = g[u][i]; 24 if(v == father)continue; 25 if(dfn[v] == 0) { 26 Tarjan(v, u); 27 low[u] = min(low[u], low[v]); 28 } else if(mark[v]) { 29 low[u] = min(low[u], dfn[v]); 30 } 31 } 32 if(low[u] == dfn[u]){ 33 int x; 34 _count++; 35 do { 36 x = S.top(); 37 S.pop(); 38 mark[x] = false; 39 color[x] = _count; 40 }while(x != u); 41 } 42 } 43 44 int main() 45 { 46 int u, v, ans; 47 while(~scanf("%d %d", &n, &m)){ 48 g.clear(); 49 g.resize(n+2); 50 while(m --){ 51 scanf("%d %d",&u, &v); 52 g[u].push_back(v); 53 g[v].push_back(u); 54 } 55 memset(dfn, 0, sizeof(dfn)); 56 memset(mark, false, sizeof(mark)); 57 cnt = _count = 0; 58 for(int i = 1; i <= n; i ++){ 59 if(dfn[i] == 0)Tarjan(i, -1); 60 } 61 if(_count == 1){ 62 puts("0"); 63 continue; 64 } 65 memset(degree, 0, sizeof(degree)); 66 for(int i = 1; i <= n; i++){ 67 for(int j = 0; j < g[i].size(); j++){ 68 if(color[i] != color[g[i][j]])degree[color[g[i][j]]] ++; 69 } 70 } 71 ans = 0; 72 for(int i = 1; i <= _count; i++){ 73 if(degree[i] == 0)ans += 2; // 孤立点 74 else if(degree[i] == 1)ans ++; // 叶子节点 75 } 76 printf("%d ", (ans + 1)/2 ); 77 } 78 return 0; 79 }