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

来源:互联网 发布:软件学报 sci 编辑:程序博客网 时间:2024/05/05 08:56

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;}


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

0 0