HDU-3018-Ant Trip-欧拉回路+并查集

Ant Trip

 这道题一开始觉得是并查集,稳了;wa

才想起来有两个重要条件

1、完全独立的点不算;

2、把点连起来的边(路)不能重复走:就是要判断欧拉回路,即每个点的度数是不是偶数;

遍历每个点,把度数为奇数的点的父节点对应的计数器加1;

最后把非独立父节点的计数器加起来:1、计数器为零的加1就可以2、非零的要除以2才行。

至于原因:

分析:我们假设n个村庄之间有k个连通分量,对于每一个连通分量,如果存在欧拉路径,那么该分量只需要一组蚂蚁就行;如果不存在欧拉路径,我们知道,要想遍历该分量所有的顶点且每条边只走一次,如果所有的顶点都有偶数个度数,那么就存在欧拉回路了,也只需要一组蚂蚁,如果存在奇数度数的顶点,而且又要想一笔画走完所有边,我们就要从这个顶点开始出发,到另一个奇数度数的顶点为止,即两个奇数度数的顶点确定一条路径,但该路径并不一定覆盖该连通分量中所有的顶点,对于其他的顶点,我们仍然遵循上面的步骤,这样对于每一个不存在欧拉路径的连通分量,需要的步数就等于该连通分量中所有奇数度顶点的个数除以2.分别把这些不存在欧拉路径的连通分量的步数加起来,然后再加上存在欧拉路径的个数,就是最终的结果了。

 

#include <bits/stdc++.h>
using namespace std;
int n,m;
int fa[100000+10];
int  cot[100000+10];
int du [100000+10];
void init(){
    for(int i=1;i<=n;i++)
        fa[i] = i;
    memset(cot,0,sizeof(cot));
    memset(du,0,sizeof(du));
}

int fin(int x)
{
    if(fa[x]==x)return x;
    else
        return     fa[x] = fin(fa[x]);

}

void uni(int x,int y)
{
    int px = fin(x);
    int py = fin(y);
    if(px==py)return ;
    else fa[px] = py;
}

int main(){
    while(~scanf("%d%d",&n,&m))
    {
        init();
        for(int i=1;i<=m;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            uni(u,v);
            du[u]++;
            du[v]++;
        }
        for(int i=1;i<=n;i++)
        {
            int papa = fin(i);
            cot[papa] += du[i]%2;
        }
        int cnt =0;
        for(int i=1;i<=n;i++)
        {
            if(fin(i)==i)
            {
                if(du[i]==0)continue;
                else
                {
                    if(cot[i]==0)cnt++;
                    else cnt+=cot[i]/2;
                }

            }
        }

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

 

posted @ 2018-02-06 20:47  ckxkexing  阅读(110)  评论(0编辑  收藏  举报