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