Ant Trip
原题来自:2009 Multi-University Training Contest 12 - Host by FZU
给你无向图的 N 个点和 M 条边,保证这 M 条边都不同且不会存在同一点的自环边,现在问你至少要几笔才能所有边都画一遍。(一笔画的时候笔不离开纸)
输入格式
多组数据,每组数据用空行隔开。 对于每组数据,第一行两个整数 N,M表示点数和边数。接下去 M 行每行两个整数 a,b,表示 a,b 之间有一条边。
输出格式
对于每组数据,输出答案。
样例
样例输入
3 3
1 2
2 3
1 3
4 2
1 2
3 4
样例输出
1
2
数据范围与提示
1≤N≤10^5,0≤M≤2×105,1<=a,b<=N
思路:
It's also a good problem
原图应是由若干个无向连通图组成的
当这个无向连通图只有一个点时,这是一个孤立点,不做操作
当这个无向连通图是一条欧拉回路或欧拉路径时,只需要一笔画即可,sum++;
当这个无向连通图有大于2个奇度点,需要用奇度点的个数的二分之一笔画完,为什么?因为一笔可以消掉两个奇度点。由于对称性的缘故,一条边的左右两端点度数分别加一,倘若原来两点都是奇度点,则两端点都会变成偶度点,反之亦然,倘若两端点度数的奇偶性不同,一者为奇一者为偶,与这两点对应的点一定有奇数个奇度点,所以一个无向连通图中不可能存在奇数个奇度点,所以只需/2即可
当然可以用并查集维护每个无向连通图
上代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
int n,m,fa[100040],de[100004],sum[100040],num[100004];
void init(){
memset(de,0,sizeof(de));
memset(sum,0,sizeof(sum));
memset(num,0,sizeof(num));
rep(i,1,n) fa[i]=i;
}
int find(int x){
if(fa[x]==x) return x;
else return fa[x]=find(fa[x]);
}
int main(){
freopen("1.txt","r",stdin) while(~scanf("%d%d",&n,&m)){
int s=0;
init();
rep(i,1,m){
int a,b;
scanf("%d%d",&a,&b);
++de[a]; ++de[b];
a=find(a); b=find(b);
if(a!=b) fa[a]=b;
}
rep(i,1,n){
if(de[i]&1) sum[find(i)]++;
num[find(i)]++;
}
rep(i,1,n){
if(num[i]==0 || num[i]==1) continue;
else if(sum[i]==0) ++s;
else s+=(sum[i]/2);
}
printf("%d\n",s);
}
return 0;
}
来源:oschina
链接:https://my.oschina.net/u/4363976/blog/3696047