VK Cup 2012 Finals, Practice Session C. Trails and Glades (欧拉回路,并查集)

15 篇文章 0 订阅
14 篇文章 0 订阅

题目描述

给定一个 n 个点, m条边的无向图, 可能有重边和自环, 求最少添加几条边,使得图中所有边都在从1出发的欧拉回路上。

 

注意点:

1、这个题强制了从 1 开始走

2、要走题目中给的所有边

3、孤立的点可以不走,如果有自环的话一定要走

4、无论什么情况,1 这个点一定要走,

思路:

这个题我用了并查集来做。然后就是分类讨论了。

并查集首先求出来有多少个联通块,这个时候,如果是孤立点的话,就不可以不算入连通块(前提是这个点不为1,如果这个点是1的话,还是要算为连通块的)

并查集之后得到几个值,

1.全是偶数度数的连通块的个数   ans,

2.存在奇数度数的连通块的个数  tot,

3. 奇数度数的点一共有多少个  num。

然后根据这三个值,我们来算最后的答案。

在 ans  <= 1  的前提下:

      如果 tot 为  0 ,那么最终答案就是 0

      如果 tot 不是0, 那么  :

              如果 ans = 0, 不考虑,

              如果ans =1,那么 把这个连通块连到  存在奇数度数的连通块上,然后 tot 不变,num不变,我们就是加了一条边而已,所以最终答案是   num/2 + 1 ; num/2 大家可以思考一下,就是把所有奇数度数的点两两连起来,而且 num 一定是偶数。

 

在 ans > 1 的情况下:

   我们把所有的偶数度数的连通块连起来,就是连了 ans-1 条边,然后变成了一个存在奇数度数的联通块,而且这个连通块的奇数度数的点 是2个,所以, tot +1, num+ 2.

最终答案就是  (ans-1)+ (num+2)/ 2;

 

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+100;
int rt[N],n,m;
int f[N],g[N],a[N],b[N];

int find(int k){
    if (k == f[k]) return k;
    return f[k] = find(f[k]);
}
int main(){
    int x,y;
    scanf("%d%d",&n,&m);
    for (int i = 0; i < m; ++i){
        scanf("%d%d",&x,&y);
        a[i] = x; b[i] = y;
        rt[x]++; rt[y]++;
    }
    for (int i = 0; i <= n; ++i){
        f[i] = i; g[i] = rt[i] % 2;
    }
    for (int i = 0; i < m; ++i){
        x = find(a[i]); y = find(b[i]);
        if (x != y){
            f[x] = y;
            g[y] += g[x];
        }
    }
    int ans = 0, tot = 0, num = 0;
    for (int i = 1; i<= n; ++i){
        if (find(i) == i && (i == 1 || rt[i])){
            if (g[i] == 0) ans++; else {
                tot++;
                num += g[i];
            }
        }
    }

    int Ans = 0;
    if (ans <= 1){
        if (tot){
            Ans = ans;
            Ans += num/2;
        }
    } else{
        Ans = ans - 1;
        num += 2;
        Ans += num / 2;
    }
    printf("%d\n",Ans);
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值