题目描述
给定一个 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;
}