[欧拉回路] CF209C Trails and Glades

填个远古的巨坑。。。。
主要是这题和当年考的题题面有点出入不然早改好直接交

码风比较远古

/*
并查集维护连通块
跑一遍图
记录每个点度数需
要加的边数为 
(偶数度数连通块数) + (奇数度数点数) / 2 -> 多个连通块时
或
(奇数点数个数) / 2 -> 单个连通块时
注意可能有重边和自环 -> 这题和模拟赛不同,它只要求存在欧拉回路
    百度学长
    如果图G中的一个路径包括每个边恰好一次,则该路径称为欧拉路径(Euler path)。
    如果一个回路是欧拉路径,则称为欧拉回路(Euler circuit)。
也就是说欧拉回路不需要考虑单独的点
但是自环的点还是要考虑的
*/

# include <iostream>
# include <cstdio>
# include <cstring>

using namespace std;

# define MAXN 1000005

int n, m, degree[MAXN];
bool vis[MAXN];
// Union-Find Set

int sum[MAXN];

int size[MAXN], fa[MAXN];

void init_ufs(int x){
    memset(vis, 0 ,sizeof(vis));
    for(int i = 1; i <= n; i++){
        size[i] = 1;
        fa[i] = i;
    }
}

int find(int x){
    return fa[x] == x ? x : fa[x] = find(fa[x]);
}

void merge(int x, int y){
    x = find(x);
    y = find(y);
    if(x == y) return;
    if(size[x] > size[y]){
        fa[y] = x;
        size[x] += size[y];
    }
    else{
        fa[x] = y;
        size[y] += size[x];
    }
}

// Main Function

int main(){
    int a, b;
    scanf("%d%d", &n, &m);
    init_ufs(n);
    vis[1] = 1; // 注意! //////////

    for(int i = 1; i <= m; i++){
        scanf("%d%d", &a, &b);
        degree[a]++, degree[b]++;

        a = find(a), b = find(b);

        if(a != b)
            merge(a, b);

        vis[size[a] > size[b] ? a : b] = 1;
    }

    int cnt = 0, ans = 0;

    for(int i = 1; i <= n; i++){
        if(i == find(i) && vis[find(i)]){
            cnt += 1;
        }
    }

    if(!vis[find(1)]){
        cnt += 1; // 注意和模拟赛不同的是这题要求必须过一号节点
    }

    for(int i = 1; i <= n; i++){
        if(degree[i] % 2){
            sum[find(i)] += 1;
        }
    }

    if(cnt == 1){
        cout<<sum[find(1)] / 2;
        return 0;
    }

    for(int i = 1; i <= n; i++){
        if(vis[i] && find(i) == i){
            ans += sum[i] / 2;
            if(!sum[i]){
                ans += 1;
            }
        }
    }    

    cout<<ans;

    return 0;
}

posted @ 2020-07-27 22:00  ChPu437  阅读(201)  评论(4编辑  收藏  举报