1. 程式人生 > 實用技巧 >[歐拉回路] CF209C Trails and Glades

[歐拉回路] 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;
}