Ant Trip【并查集】【欧拉图】【一笔画问题】

7 篇文章 0 订阅

 这一道题的知识储量是比较大的,我们要知道欧拉图的数量,然后再加上奇数度的节点数/2(因为奇数度节点也是成双成对出现在一个子串中的)才能得到最终的答案。

先上题:

Ant Trip

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 4093    Accepted Submission(s): 1590


 

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.

 

 

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.

 

  这是一道比较有思想的那么一道题,首先,我们对于关联的点建树,将他们放进同一颗树中,于此同时,两个点的度都要同时加一,用以判断之后奇数度的个数(我用vis[]记录该点度的个数)。 之后,既然已经确定了所有节点的根结点,我们就能对他们的根进行操作,我们遍历每一个点的根结点(因为要通过根结点存储这颗树上的奇数度的个数),将每个根结点放进vector结构中保存起来(这里是因为我们不知道根节点将会有多少个,所以用vector更加方便一些),然后如果该点为奇数度点,根结点记录下的奇数度的个数+1(这里可能有点绕,就是中途遇到奇数度点都则根记录下的奇数度节点数+1)。 最终一一遍历所有的根结点即可,特殊的:0度的根说明没有与其相连的边,则不需要笔画(错多了,得出的结论);然后,如果奇数度个数为0,那么构成欧拉回路,直接ans+1;其他的(奇数度),就是奇数度情况了“/2”即可。

 

完整代码:

//Ant Trip
#include <iostream>     //并查集、欧拉图
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <queue>
using namespace std;
typedef long long ll;
int N,M;
int vis[100005];        //记录 度
int root[100005];       //记录 根
int odd[100005];        //奇数度根结点数
bool used[100005];      //访问根结点时判断是否使用过这样的根
vector<int> v;          //把这样的根都存进去
int fid(int x)          //找前导点、根
{
    if(x==root[x]) return x;
    return root[x]=fid(root[x]);
}
void join(int x, int y)         //载入、合并
{
    if(fid(x)!=fid(y))
    {
        root[fid(x)]=fid(y);        //y的根也成为x那条支路的根
    }
}
int main()
{
    while(scanf("%d%d",&N,&M)!=EOF)
    {
        v.clear();                      //初始化
        memset(vis, 0, sizeof(vis));
        memset(root, 0, sizeof(root));
        memset(odd, 0, sizeof(odd));
        memset(used, false, sizeof(used));
        for(int i=1; i<=N; i++) root[i]=i;      //自己是自己的根结点
        for(int i=0; i<M; i++)
        {
            int e1,e2;
            scanf("%d %d",&e1,&e2);
            vis[e1]++;
            vis[e2]++;
            join(e1, e2);
        }
        for(int i=1; i<=N; i++)
        {
            int boss=fid(i);        //找到根结点
            if(!used[boss])
            {
                v.push_back(boss);
                used[boss]=true;
            }
            if(vis[i]%2)
                odd[boss]++;
        }
        if(N==1)        //此时直接处理,就一个点,不需要管
        {
            printf("0\n");
            continue;
        }
        int sum=0;
        for(int i=0; i<v.size(); i++)
        {
            int k=v[i];
            if(vis[k]==0) continue;     //0度则不做处理,一个点,不需要笔画
            if(odd[k]==0) sum++;        //说明构成欧拉回路
            else sum+=odd[k]/2;         //奇数度的情况,加一半
        }
        printf("%d\n",sum);
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wuliwuliii

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值