CF36 E Two Paths——欧拉(回)路

题目:http://codeforces.com/contest/36/problem/E

给定一张无向图,要求输出两条欧拉路覆盖所有边;

分类讨论,首先判-1:有两个以上连通块 / 有四个以上奇度数点 / 只有一条边 / 有两个连通块而其中一个连通块里有四个奇度数点 (/ 有连通块里有奇数个奇度数点);

然后分两个连通块和一个连通块的情况进行 dfs 找欧拉路(模板 dfs );

注意可能没有奇度数的点,也就是有欧拉回路,所以不仅找奇度数点进行 dfs ,还要在那之后 dfs 仍然没有被走过的点;

明明是模仿题解写的竟然还调了两小时...码力++...

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int const maxn=10005;
int n,m,d[maxn],ans[maxn],tot,fa[maxn],cnt,c[maxn],hd[maxn],ct=1;
bool vis[maxn],used[maxn];
struct N{
    int to,nxt;
    N(int t=0,int n=0):to(t),nxt(n) {}
}ed[maxn<<1];
void add(int x,int y){ed[++ct]=N(y,hd[x]); hd[x]=ct;}
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
void dfs(int x)
{
    vis[x]=1;
    for(int i=hd[x];i;i=hd[x])
    {
        hd[x]=ed[i].nxt;
        if(used[i>>1])continue;
        used[i>>1]=1; dfs(ed[i].to); ans[++tot]=(i>>1);
    }
}
int main()
{
    freopen("input.txt","r",stdin);
    freopen("output.txt","w",stdout);
    n=10000; scanf("%d",&m);//不能是 n=10005
    for(int i=1;i<=n;i++)fa[i]=i;//!!
    for(int i=1,x,y;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        add(x,y); add(y,x); d[x]++; d[y]++;
        if(find(x)!=find(y))fa[find(x)]=find(y);
    }
    for(int i=1;i<=n;i++) if(d[i]&1) c[find(i)]++;
    for(int i=1;i<=n;i++) if(c[i]&1){printf("-1\n"); return 0;}
    for(int i=1,sum=0;i<=n;i++)
    {
        if(d[i])cnt+=(i==find(i));
        if(c[i])sum+=c[i];
        if(sum>4){printf("-1\n"); return 0;}
    } 
    if(cnt>2){printf("-1\n"); return 0;}
    if(cnt==2)
    {
        for(int i=1;i<=n;i++) if(c[i]==4){printf("-1\n"); return 0;}
        for(int i=1;i<=n;i++)
            if(!vis[i]&&(d[i]&1))
            {
                tot=0; dfs(i); printf("%d\n",tot);
                for(int j=tot;j;j--)printf("%d ",ans[j]); printf("\n");
            }
        for(int i=1;i<=n;i++)//欧拉回路 
            if(!vis[i]&&d[i])
            {
                tot=0; dfs(i); printf("%d\n",tot);
                for(int j=tot;j;j--)printf("%d ",ans[j]); printf("\n");
            }
    }
    else
    {
        bool fl=0;
        for(int i=1;i<=n;i++) if(c[i]==4)fl=1;
        if(fl)
        {
            for(int i=1;i<=n;i++)    if(d[i]&1)
            {
                for(int j=i+1;j<=n;j++)
                    if(d[j]&1){d[i]++; d[j]++; add(i,j); add(j,i); break;}
                break;
            }
            for(int i=1;i<=n;i++)
                if(!vis[i]&&(d[i]&1)){tot=0; dfs(i); break;}
            for(int i=1;i<=tot;i++)    if(ans[i]==m+1)
            {
                printf("%d\n",i-1);
                for(int j=1;j<i;j++)printf("%d ",ans[j]); printf("\n");
                printf("%d\n",tot-i);
                for(int j=i+1;j<=tot;j++)printf("%d ",ans[j]);
                break;
            }
        }
        else
        {
            for(int i=1;i<=n;i++)
                if(!vis[i]&&(d[i]&1)){tot=0; dfs(i);}
            for(int i=1;i<=n;i++)//欧拉回路 
                if(!vis[i]&&d[i]){tot=0; dfs(i);}
            if(tot<=1){printf("-1\n"); return 0;}//只有一条边 
            printf("1\n%d\n%d\n",ans[1],tot-1);
            for(int i=2;i<=tot;i++)printf("%d ",ans[i]);
        }
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Zinn/p/9279336.html
今日推荐