1. 程式人生 > >Ant Trip(歐拉回路+並查集)

Ant Trip(歐拉回路+並查集)

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;
}