Ant Trip
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2560 Accepted Submission(s): 1009
Problem Description
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.
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
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 2HintNew ~~~ 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.
Source
Recommend
题意:一笔画问题,求出最少需要画几笔能够遍历所有的点。
分析:对于一笔画问题,对于一个连通块,除了欧拉回路的情况,其他的情况需要的笔数都是 连通块奇数度的点的个数/2 。根据此定理可以先用并查集判断连通块,注意此题终点的孤立点是不需要计数的,此时需要添加vis数组,只要有一条边的起点或者终点含有则说明其不是孤立点。在判断完连通块后可以扫描一遍奇数度数的点并计数,此时需要一个mark数组标记它的那一块的最初始元素为访问,为下一遍扫描时统计欧拉回路个数做好准备。在统计完奇数度点的个数cnt后,res+=cnt/2。下一次循环时寻找出欧拉回路的个数即可。见AC代码:
//一笔画问题
//欧拉回路或者欧拉路的话都可以一笔画
//一个连通块想要遍历所有的边需要 奇度个数/2 笔
#include<stdio.h>
#include<string.h>
#include<set>
using namespace std;
const int maxn=1e5+5;
int pre[maxn];
int io[maxn];
int vis[maxn];
int used[maxn];
int mark[maxn];
set<int> s;
int find(int x)
{
int r=x;
while (pre[r]!=r)
r=pre[r];
int i=x,j ;
while( i != r )
{
j=pre[i];
pre[i]=r ;
i=j;
}
return r ;
}
void join(int x,int y)
{
int fx=find(x),fy=find(y);
if(fx!=fy)
pre[fx]=fy;
}
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m))
{
for(int i=0; i<=n; i++)
pre[i]=i;
for(int i=0; i<=n; i++)
{
io[i]=0;
vis[i]=0;
used[i]=0;
}
int u,v;
while(m--)
{
scanf("%d%d",&u,&v);
io[u]++;
io[v]++;
vis[u]=1;//标记其访问过 则说明它不是孤立点
vis[v]=1;
join(u,v);
}
for(int i=1; i<=n; i++)
if(vis[i])
s.insert(find(i));
int res=0,cnt=0;
for(int i=1; i<=n; i++)
{
if(io[i]%2==1&&vis[i])
{
if(!mark[find(i)])
mark[find(i)]=1;//标记已经处理过的连通块
cnt++; //奇度点的个数
used[i]=1; //优化 在下一轮判断欧拉回路的时候不遍历已经遍历过的点
}
}
res+=cnt/2;
for(int i=1; i<=n; i++)
{
if(vis[i]&&!mark[find(i)]&&!used[i])//此时得到的都是 欧拉回路 能够一笔画的情况
{
res++;
mark[find(i)]=1;
}
}
printf("%d\n",res);
//s.clear();
/*set<int>::iterator it;
for(it =s.begin(); it!=s.end(); it++)//两重循环会超时
{
int cnt=0;
for(int j=1; j<=n; j++)
if(find(j)==(*it)&&vis[j]&&io[j]%2==1&&!used[j])
{
cnt++;
used[j]=1;
}
if(cnt==1||cnt==0)
res++;
else
res+=cnt/2;
}
printf("%d\n",res);*/
}
}
刚开始写的时候,将不同的连通块放入了set,再二重循环遍历判断个数时因为数据量很大,所以T了。看来满足于得出结果还是太天真。
特记下,以备后日回顾。