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
思路: 一笔画问题,对于一个连通块,如果是欧拉回路,一笔即可(如果这个无向图只有一个点,0笔,不用特判,因为根本进不去),除了欧拉回路的情况,其他的情况需要的笔数都是 连通块奇数度的点的个数/2
AC代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int N=2e5+100;
int du[N],f[N],book[N];
int n,m;
void init()
{
for(int i=0;i<n;i++)
f[i]=i;
}
int find(int x)
{
if(f[x]==x)
return f[x];
return f[x]=find(f[x]);
}
void merge(int x,int y)
{
int xx=find(x);
int yy=find(y);
if(xx!=yy)
f[yy]=xx;
}
int main()
{
int i,j,k,a,b;
while(~scanf("%d%d",&n,&m))
{
init();
memset(du,0,sizeof(du));
memset(book,0,sizeof(book));
for(i=0;i<m;i++)
{
scanf("%d%d",&a,&b);
merge(a,b);//并查集将图分块
du[a]++;
du[b]++;
}
int sum=0,ans=0;
for(i=1;i<=n;i++)
{
if(du[i]%2)//半欧拉里面奇数点的个数
{
book[find(i)]=1;//标记根节点
sum++;
}
}
for(i=1;i<=n;i++)
{
if(!book[i]&&du[i]>0&&f[i]==i)//欧拉回路个数
ans++;
}
printf("%d\n",sum/2+ans);
}
return 0;
}