Description
hdu 3018 Ant Trip
Ant Country consist of N towns.There are M roads connecting the towns.
Ant Tony,together with his friends,wants to go through every part of the country.
Input
Input contains multiple cases.Test cases are separated by several blank lines.Each test case starts with two integer N(1<=N<=100000),M(0<=M<=200000),indicating that there are N towns and M roads in Ant Country.Followed by M lines,each line contains two integers a,b,(1<=a,b<=N) indicating that there is a road connecting town a and town b.No two roads will be the same,and there is no road connecting the same town.
Output
For each test case ,output the least groups that needs to form to achieve their goal.
Sample Input
3 3
1 2
2 3
1 3
4 2
1 2
3 4
Sample Output
1
2
Hint
New ~~~ Notice: if there are no road connecting one town ,tony may forget about the town.
In sample 1,tony and his friends just form one group,they can start at either town 1,2,or 3.
In sample 2,tony and his friends must form two group.
解题思路:先说明一下题意,就是有n个城市,有m条路,每条路都不能重复走,问需要出发几次才能把所有的路都走过一遍的。形象的就是说一笔画的问题,n个点,m个路线,一共需要几笔才能画完,是一道欧拉回路的简单扩展题目(欧拉回路,1.必须是连通图 2.所有点的度都必须是偶数)。
首先,我们要走的是这m条路,所以孤立存在的点就不用考虑了,然后对于单独存在的欧拉回路出现一次就可以记上一次,但是要知道,每一个小的欧拉回路必须要单独存在。如果与其他路线相连,只需要计算上一次就可以了。然后考虑的就是欧拉回路之外的点了,他们就是那些度为奇数的点,出现一次就统计一次,最后奇数度点数/2+单独存在欧拉回路数就是结果了。为什么奇数度点的个数要除以2呢,因为奇数度的点就只能经过奇数次,不像偶数度,走过去之后还能往回走。经过奇数次之后就回不去了,也就是到达了另外一个奇数度的点,出现了两个奇数度的点但是存在于一笔之中。所以这里除以2就可以了。
总笔画数=奇数度点数/2+单独存在欧拉回路数。
AC代码
#include <stdio.h>
#include <string.h>
int pur[100010]; //并查集数组标记父亲
int f[100010]; //存储每个点的度
int mark[100010]; //标记父亲这一点是否已经走过
int find(int x)
{
if(x==pur[x])
return x;
return find(pur[x]);
}
void merge(int x,int y)
{
int t;
int u=find(x);
int v=find(y);
if(u<v)
t=v,v=u,u=t;
pur[u]=v;
return ;
}
int main()
{
int n,m,a,b;
int i,j,yy;
while(scanf("%d%d",&n,&m)!=EOF){
for(i=1;i<=n;i++) //数据初始化
pur[i]=i;
memset(f,0,sizeof(f));
memset(mark,0,sizeof(mark));
for(i=0;i<m;i++){
scanf("%d%d",&a,&b);
f[a]++; //记录每个点的度
f[b]++;
merge(a,b); //合并两个点
}
yy=0;
for(i=1;i<=n;i++){
if(f[i]%2){ /*判断该点度数如果为奇数
就加上去,然后将其父亲标记为1 */
yy++;
mark[find(i)]=1;
}
}
yy/=2;
for(i=1;i<=n;i++){
if(!f[i]) //单独存在的点没有路,直接跳过即可
continue;
if(mark[find(i)]==0&&find(i)==i)
yy++; /*如果这个点与其他点能构
成欧拉回路的话(也就是能够一笔画成),并且与奇数度不相连的话就需要重新开
一条路,这时候yy才会自增。如果相连的话mark就已经将其父亲标记为1了,
就在奇数度的时候已经计算过就不用加了。*/
}
printf("%d\n",yy);
}
return 0;
}