hdu 3018 欧拉路定理+并查集

题目:hdu 3018
题意:
有一些道路,每次只能走一遍,问最少几次走遍所有道路?
分析:
这题是经典问题:一笔画问题。解决这个问题,需要知道几个定理和定义:
1. 欧拉道路:能否从无向图中的一个节点出发走出一条道路,每条边恰好经过一次,这样的路线称为欧拉道路。
2. 如果一个图是联通的且最多只有两个奇度点,则一定存在欧拉道路。如果有两个奇度点,则必须从其中一个出发,回到另一个终止。如果没有奇度点,可以从任一点出发。
3. 对于有向图,如果想构成欧拉路,那么:最多只能有两个点的入读不等于出度,而且必须是其中一个点的出度比入度大一,另一个点的入度比出度大一。

对于这题:先用并查集找出连通图,然后再找出每个连通块中奇度点的个数,如果没有奇度点,那么只需要一笔,如果有奇度点,那么需要奇点的个数/2笔。另外,这题独立点需要忽略掉。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long ll;
const int N=100000+5;
int fa[N];
int findfa(int x){return x==fa[x]?x:fa[x]=findfa(fa[x]);}
int de[N],cnt[N],vis[N];
int main()
{
    int n,m;
    while(~scanf("%d%d",&n,&m)){
        for(int i=1;i<=n;i++)fa[i]=i;
        memset(de,0,sizeof(de));
        memset(vis,0,sizeof(vis));
        memset(cnt,0,sizeof(cnt));
        int u,v;
        for(int i=0;i<m;i++){
            scanf("%d%d",&u,&v);
            de[u]++;de[v]++;
            int x=findfa(u),y=findfa(v);
            if(x!=y)fa[x]=y;
        }
        vector<int>ans;
        for(int i=1;i<=n;i++){
            int x=findfa(i);
            if(!vis[x]){
                vis[x]=1;
                ans.push_back(x);
            }
            if(de[i]&1){
                cnt[x]++;
            }
        }
        int sum=0;
        for(int i=0;i<ans.size();i++){
            int x=ans[i];
            if(de[x]==0)continue; //独立点忽略掉
            if(cnt[x]==0)sum++;
            else sum+=cnt[x]/2;
        }
        printf("%d\n",sum);
    }
    return 0;
}
posted @ 2016-03-23 21:19  HARD_UNDERSTAND  阅读(197)  评论(0编辑  收藏  举报