hdu 3018 欧拉路定理+并查集

来源:互联网 发布:网游数据库 编辑:程序博客网 时间:2024/06/03 04:48

题目: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;}
0 0
原创粉丝点击