Ant Trip(HDU 3018)---多笔画问题

题目链接

题目描述

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. 欧拉通路/回路的判定
  2. 一笔画/多笔画问题

欧拉通路/回路的判定

有向图

  • 欧拉通路:图是连通的,图中只有两个奇度点,分别是欧拉通路的两个端点。对于欧拉通路,除起点、终点外,每个点如果进入,显然一定要出去,因此都是偶点。
  • 欧拉回路:图是连通的,点均为偶度点。对于欧拉回路,每个点进入、出去的次数相等,因此没有奇点。

无向图

  • 欧拉通路:图是连通的,除两顶点外其余点的入度等于出度,且这两个顶点中,一个顶点入度比出度大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;
	}
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值