题目描述
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.
They intend to visit every road , and every road must be visited for exact one time.However,it may be a mission impossible for only one group of people.So they are trying to divide all the people into several groups,and each may start at different town.Now tony wants to know what is the least groups of ants that needs to form to achieve their goal.输入格式
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.
输出格式
For each test case ,output the least groups that needs to form to achieve their goal.
输入样例
3 3
1 2
2 3
1 3
4 2
1 2
3 4输出样例
1
2提示/说明
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.
分析
显然,本题是一个欧拉通路/回路笔画问题。因此可以分为两个方向讨论:
- 欧拉通路/回路的判定
- 一笔画/多笔画问题
欧拉通路/回路的判定
有向图
- 欧拉通路:图是连通的,图中只有两个奇度点,分别是欧拉通路的两个端点。对于欧拉通路,除起点、终点外,每个点如果进入,显然一定要出去,因此都是偶点。
- 欧拉回路:图是连通的,点均为偶度点。对于欧拉回路,每个点进入、出去的次数相等,因此没有奇点。
无向图
- 欧拉通路:图是连通的,除两顶点外其余点的入度等于出度,且这两个顶点中,一个顶点入度比出度大1(起点),另一个入度比出度小1(终点)
- 欧拉回路:图是连通的,图中所有点的入度等于出度。
一笔画/多笔画判定
一笔画判定
一笔画的图只需满足以下两个条件,即:
- 图是连通图
- 奇度点的个数为0或2
多笔画问题
由于连通图奇度点的个数为偶数,因此有:
- 最少笔画数=奇度点数/2
思路
由于图中可能存在多个联通分量,每个联通分量都是可以一笔画或者多笔画完成的,那么该问题的答案=欧拉回路数+奇度点数。
因此,首先统计奇度点个数,并将存在奇度点的联通分量标记起来(因为他是需要多笔画完成的,不存在欧拉回路),那么剩下的联通分量都是可以一笔画完成的欧拉回路。
源程序
#include <bits/stdc++.h>
#define MAXN 100005
using namespace std;
int n,m,degree[MAXN],father[MAXN];
bool used[MAXN];
int read() //快读
{
int sum=0;
char c=getchar();
while(c<'0'||c>'9')c=getchar();
while(c>='0'&&c<='9'){
sum=sum*10+c-'0';
c=getchar();
}
return sum;
}
int find(int x) //并查集
{
if(x==father[x])return x;
return father[x]=find(father[x]); //路径压缩
}
void Union(int x,int y) //合并
{
x=find(x);
y=find(y);
if(x!=y)father[x]=y;
return ;
}
int main()
{
while(cin>>n>>m){
for(int i=1;i<=n;i++)degree[i]=0,father[i]=i;//初始化
for(int i=1;i<=m;i++){ //统计顶点度数以及并查集
int x=read(),y=read();
degree[x]++;
degree[y]++;
Union(x,y);
}
int cnt,num=0; //统计奇度点个数
for(int i=1;i<=n;i++)
if(degree[i]&1){
num++;
used[find(i)]=true; //标记已计算过的连通分量
}
cnt=num/2; //非欧拉回路笔画数=奇度点数除以2
for(int i=1;i<=n;i++)
if(degree[i]!=0){ //排除孤点
if(!used[find(i)]){ //计算欧拉回路的一笔画数
used[find(i)]=true;
cnt++;
}
}
cout<<cnt<<endl;
}
}