hdu 3018Ant Trip(一笔画问题,用并查集就无向图的连通分量)

1.题意:给一个无向简单图,问至少几笔画画完所有的边。

2.思路:①先用并查集求出有几个连通分量;②如果连通分量中只有一个结点,那么就是0笔画;③在一个简单无向连通图中,如果没有欧拉回路,至少要用n/2笔画画完所有边,n是奇点个数。

3AC代码一(93ms):

#include<cstdio>
#include<cstring>
#include<set>
#include<vector>
using namespace std;

int n,m;
int father[100005];
int deg[100005];//每个结点的度
int vis[100005];
int odd_cnt[100005];
vector<int> vec;

int Find(int a)
{
    int r=a;
    while(father[a]!=a)
    {
        a=father[a];
    }
    father[r]=a;
    return a;
}

inline void Union(int a,int b)
{
    a=Find(a);
    b=Find(b);//千万不要写成father[b]啊啊啊!!!!!!!!!!!!!!!!1
    if(a!=b)
    {
        father[b]=a;
    }
}

int main()
{
    int ans;
    while(scanf("%d%d",&n,&m)==2)
    {
        ans=0;
        vec.clear();
        for(int i=1; i<=n; i++)
        {
            father[i]=i;
            deg[i]=0;
            vis[i]=0;
            odd_cnt[i]=0;
        }
        for(int i=0; i<m; i++)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            deg[a]++;
            deg[b]++;
            Union(a,b);
        }
        for(int i=1; i<=n; i++)
        {
            father[i]=Find(i);
            if(vis[father[i]]==0)
            {
                vec.push_back(father[i]);
                vis[father[i]]=1;
            }
            if(deg[i]%2)
                odd_cnt[father[i]]++;
        }
        for(int i=0;i<vec.size();i++)
        {
            int f=vec[i];
            if(deg[f]==0)
                continue;
            if(odd_cnt[f]==0)
                ans=ans+1;
            else
                ans=ans+odd_cnt[f]/2;//在一个简单无向连通图中,如果没有欧拉回路,至少要用n/2笔画画完所有边,n是奇点个数

        }
        printf("%d\n",ans);
    }
    return 0;
}

AC代码二(156ms):

#include<cstdio>
#include<cstring>
#include<set>
using namespace std;

struct Node
{
    int num;
    set<int> st;
    void init()
    {
        num=0;
        st.clear();
    }
};

int n,m;
int father[100005];
Node son[100005];//结点i的儿子的个数son[i].num,然后装在集合st里
int deg[100005];//每个结点的度

int Find(int a)
{
    int r=a;
    while(father[a]!=a)
    {
        a=father[a];
    }
    father[r]=a;
    return a;
}

void Union(int a,int b)
{
    a=Find(a);
    b=Find(b);
    if(a!=b)
    {
        father[b]=a;
    }
}

int main()
{
    int ans;
    while(scanf("%d%d",&n,&m)==2)
    {
        ans=0;
        for(int i=1; i<=n; i++)
        {
            father[i]=i;
            //son[i]=0;
            deg[i]=0;
            son[i].init();
        }
        for(int i=0; i<m; i++)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            deg[a]++;
            deg[b]++;
            Union(a,b);
        }
        for(int i=1; i<=n; i++)
        {
            father[i]=Find(i);
            son[father[i]].num++;
            son[father[i]].st.insert(i);
        }
        for(int i=1; i<=n; i++)
        {
            if(son[i].num>=2)
            {
                set<int>::iterator it;
                int cnt=0;
                for(it=son[i].st.begin(); it!=son[i].st.end(); it++)
                {
                    if(deg[*it]%2)
                        cnt++;
                }
                if(!cnt)
                    ans+=1;
                else
                    ans=ans+cnt/2;//在一个简单无向连通图中,至少要用n/2笔画画完所有边,n是奇点个数
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

AC代码三(78ms):

#include<cstdio>
#include<cstring>
#include<set>
using namespace std;

struct Node
{
    int son_num;
    int odd_son_num;
    void init()
    {
        son_num=0;
        odd_son_num=0;
    }
};

int n,m;
int father[100005];
Node son[100005];//结点i的奇点儿子的个数son[i]
int deg[100005];//每个结点的度

int Find(int a)
{
    int r=a;
    while(father[a]!=a)
    {
        a=father[a];
    }
    father[r]=a;
    return a;
}

inline void Union(int a,int b)
{
    a=Find(a);
    b=Find(b);
    if(a!=b)
    {
        father[b]=a;
    }
}

int main()
{
    int ans;
    while(scanf("%d%d",&n,&m)==2)
    {
        ans=0;
        for(int i=1; i<=n; i++)
        {
            father[i]=i;
            //son[i]=0;
            deg[i]=0;
            son[i].init();
        }
        for(int i=0; i<m; i++)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            deg[a]++;
            deg[b]++;
            Union(a,b);
        }
        for(int i=1; i<=n; i++)
        {
            father[i]=Find(i);
            son[father[i]].son_num++;
            if(deg[i]%2)
                son[father[i]].odd_son_num++;

        }
        for(int i=1;i<=n;i++)
        {
            if(son[i].son_num>=2)
            {
                if(!son[i].odd_son_num)
                    ans+=1;
                else
                    ans=ans+son[i].odd_son_num/2;//在一个简单无向连通图中,至少要用n/2笔画画完所有边,n是奇点个数
            }
        }
        /*for(int i=1; i<=n; i++)
        {
            if(son[i].num>=2)
            {
               // printf("%d\n",son[i].num);
                set<int>::iterator it;
                int cnt=0;
                for(it=son[i].st.begin(); it!=son[i].st.end(); it++)
                {
                    //printf("%d\n",*it);
                    if(deg[*it]%2)
                        cnt++;
                }
                if(!cnt)
                    ans+=1;
                else
                    ans=ans+cnt/2;//在一个简单无向连通图中,至少要用n/2笔画画完所有边,n是奇点个数
            }
        }*/
        printf("%d\n",ans);
    }
    return 0;
}

以上代码只是在计算每个连通分量要几笔画 的实现方法不同

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-25 11:17:10

hdu 3018Ant Trip(一笔画问题,用并查集就无向图的连通分量)的相关文章

hdu 1829 A Bug&#39;s Life (基础并查集)

题目: 链接:点击打开链接 题意: 给定虫子的交配关系,确定实验是否支持教授的假设即没有同性恋或者不符合假设. 思路: 是一道基础的并查集题目.存在两个集合异性和同性,给出多组关系,看这两个集合有木有联系,即是否有同性恋. 定义一个数组sex[],sex[i]表示与编号i的性别相反的虫子编号.然后将和i虫子有联系的合并为同一个集合(认为是同性的).如果findset(u) == findset(v),出现了反常行为. 代码: #include <iostream> #include <c

HDU 1829 A Bug&#39;s Life (并查集)

题目链接:请戳这里. 题目大意及思路:给定n个Bugs(shen me gui)和m对Bugs之间的关系,假定关系是两个Bugs的男女关系,那么问存不存在同性恋的情况. 那么若a与b是男女关系,b与c是男女关系,那么a和c的性别我们就可以认为是相同的.我们用可以建立两个并查集,一类放男男关系,一类放女女关系. 那么若男男关系中出现了环的情况(即有共同的根),那么同性恋关系就出现了. #include<iostream> #include<cstdio> #include<cs

hdu 1198 Farm Irrigation (搜索或并查集)

Farm Irrigation Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 5818    Accepted Submission(s): 2521 Problem Description Benny has a spacious farm land to irrigate. The farm land is a rectangle

HDU 1272: 小希的迷宫(并查集)

小希的迷宫 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 25010    Accepted Submission(s): 7683 Problem Description 上次Gardon的迷宫城堡小希玩了很久(见Problem B),现在她也想设计一个迷宫让Gardon来走.但是她设计迷宫的思路不一样,首先她认为所有的通道都应该是

HDU 2120 Ice_cream&#39;s world I【并查集】

解题思路:给出n对点的关系,求构成多少个环,如果对于点x和点y,它们本身就有一堵墙,即为它们本身就相连,如果find(x)=find(y),说明它们的根节点相同,它们之间肯定有直接或间接的相连,即形成环 样例的示意图 共3个环 Ice_cream's world I Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 642    Acce

HDU 1102 Constructing Roads (裸的并查集)

Constructing Roads Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 13210    Accepted Submission(s): 4995 Problem Description There are N villages, which are numbered from 1 to N, and you should

hdu 1598 find the most comfortable road (并查集 + 枚举)

题目: 链接:点击打开链接 思路: 对边排序,再枚举每条边,如果出现通路(findset(x) == findset(y))就结束. 代码: #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define MAXN 220 #define MAXM 1010 #define MAX 100000000 stru

HDU 1598 find the most comfortable road (并查集||最短路)

find the most comfortable road Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 3720    Accepted Submission(s): 1583 Problem Description XX星有许多城市,城市之间通过一种奇怪的高速公路SARS(Super Air Roam Structure---超级

Ant Trip HDU - 3018(欧拉路的个数 + 并查集)

题意: Ant Tony和他的朋友们想游览蚂蚁国各地. 给你蚂蚁国的N个点和M条边,现在问你至少要几笔才能所有边都画一遍.(一笔画的时候笔不离开纸) 保证这M条边都不同且不会存在同一点的自环边. 也就是蚂蚁分组遍历整个无向图,他们试图把所有的人分成几个小组,每个小组可以从不同的城镇开始. Tony想知道最少需要几组.  Input输入包含多组测试用例,由多个空行分隔. 每个测试用例的第一行是两个整数N(1<=N<=100000).M(0<=M<=200000),表明蚂蚁国有N个城镇