Ant Trip(欧拉回路+并查集)

末鹿安然 提交于 2020-05-01 11:33:34

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

数据范围与提示

1N10^5,0M2×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;
}

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!