FZU 2112 并查集、欧拉通路

原题:http://acm.fzu.edu.cn/problem.php?pid=2112

  首先是,票上没有提到的点是不需要去的。

  然后我们先考虑这个图有几个连通分量,我们可以用一个并查集来维护,假设有n个连通分量,我们就需要n-1条边把他们连起来。

  最后对于每个联通分量来说,我们要使它能一次走完,就是要求他是否满足欧拉通路,也就是这个联通分量中至多有2个度为奇数的点,每多出2个度为奇数的点,就多需要一条边(因为单个连通分量的所有点的度数之和为偶数,所以不可能存在奇数个奇数度数的点)。

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<algorithm>
 4 #define maxn 111111
 5 using namespace std;
 6 int f[maxn],du[maxn],odd[maxn],book[maxn];
 7 int getf(int v){
 8     if(f[v] == v){
 9         return v;
10     }else{
11         f[v] = getf(f[v]);
12         return f[v];
13     }
14 }
15 void merge(int u,int v){
16     int a = getf(u);
17     int b = getf(v);
18     if(a!=b)
19         f[b] = a;
20 }
21 int main(){
22     int t;
23     scanf("%d",&t);
24     while(t--){
25         memset(du,0,sizeof(du));//统计每个节点的度数
26         memset(odd,0,sizeof(odd));//统计每个联通分量度数为奇数的节点个数
27         memset(book,0,sizeof(book));//标记该点是否需要去
28         int n,m;
29         scanf("%d%d",&n,&m);
30         for(int i = 1;i<=n;i++)//初始化
31             f[i] = i;
32         int u,v;
33         while(m--){
34             scanf("%d%d",&u,&v);
35             du[u]++;
36             du[v]++;
37             book[u] = 1;
38             book[v] = 1;
39             merge(u,v);
40         }
41         int cnt = 0;//需要边的数量
42         for(int i = 1;i<=n;i++){
43             if(book[i]){
44                 if(f[i] == i)
45                     cnt++;
46                 if(du[i]&1)//度数为奇数时,对其并查集根节点的值进行更新
47                     odd[getf(i)]++;
48             }
49         }
50         for(int i = 1;i<=n;i++){
51             if(f[i] == i)
52                 cnt += max(0,(odd[i]-2)/2);//统计每个联通分量的度数为奇数的节点所需要的边的个数
53         }
54         printf("%d
",cnt-1);
55     }
56     return 0;
57 }
原文地址:https://www.cnblogs.com/zqy123/p/5525007.html