Uoj117 欧拉回路

试题描述
有一天一位灵魂画师画了一张图,现在要你找出欧拉回路,即在图中找一个环使得每条边都在环上出现恰好一次。
一共两个子任务:
这张图是无向图。
这张图是有向图。
输入
第一行一个整数 t,表示子任务编号。t∈{1,2},如果 t=1 则表示处理无向图的情况,如果 t=2 则表示处理有向图的情况。
第二行两个整数 n,m,表示图的结点数和边数。
接下来 m 行中,第 i 行两个整数 vi,ui​​ ,表示第 i 条边(从 1 开始编号)。保证 1≤vi,ui≤n。
如果 t=1 则表示 vi​  到 ui​​  有一条无向边。
如果 t=2则表示 vi有一条有向边。
图中可能有重边也可能有自环。
输出
如果不可以一笔画,输出一行 NO。
否则,输出一行 YES,接下来一行输出一组方案。
如果 t=1,输出 m 个整数 
p1,p2,…,pm。令 e=∣pi∣,那么 e 表示经过的第 i 条边的编号。如果 pi为正数表示从 ve走到 ue,否则表示从 ue走到 ve。
如果 t=2,输出 m 个整数 p1,p2,…,pm。其中 pi表示经过的第 i 条边的编号。
输入示例
样例输入 1
1
3 3
1 2
2 3
1 3
样例输入 2
2
5 6
2 3
2 5
3 4
1 2
4 2
5 1
输出示例
样例输出 1
YES
1 2 -3
样例输出 2
YES
4 1 3 5 2 6
其他说明
数据范围与提示
1≤n≤10^5,0≤m≤2×10^5

欧拉回路的模板,两种都包含了

首先是特判,关系到欧拉回路的定义

对于无向图,每个点的度都要为偶数

对于有向图,每个点的入度要和出度相等

然后是DFS判环,记录每条边是否走过,对于无相变要加一个特判

因为无向图的邻接表会连两条,而编号只有从1到m

而我们又知道,从左到右的边的编号是奇数,反之则是偶数

所以只需要进行奇偶的判断,然后将反向的边也染色

最后输出的时候也要特判,无向图要把编号除2,然后判断正负(根据题意)

下面给出代码:

#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
using namespace std;
inline int rd(){
    int x=0,f=1;
    char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1;
    for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
    return x*f;
}
inline void write(int x){
    if(x<0) putchar('-'),x=-x;
    if(x>9) write(x/10);
    putchar(x%10+'0');
    return ;
}
int f,n,m;
int head[200006],nxt[400006],to[400006];
int total=0;
void add(int x,int y){
    total++;
    to[total]=y;
    nxt[total]=head[x];
    head[x]=total;
    return ;
}
int du[200006],in[200006],out[200006];
int tot=0;
int vis[400006];
int ans[400006];
void dfs(int x){
    for(int &e=head[x];e;e=nxt[e]){
        if(!vis[e]){
            int k=e;
            vis[e]=1;
            if(f==1){
                if(e%2) vis[e+1]=1;
                else vis[e-1]=1;
            }
            dfs(to[e]);
            ans[++tot]=k;
        }
    }
    return ;
}
int main(){
    f=rd(),n=rd(),m=rd();
    for(int i=1;i<=m;i++){
        int x=rd(),y=rd();
        add(x,y);
        in[y]++,out[x]++;
        if(f==1) add(y,x),du[x]++,du[y]++;
    }
    if(f==1) for(int i=1;i<=n;i++) if(du[i]%2){
        printf("NO");
        return 0;
    }
    if(f==2) for(int i=1;i<=n;i++) if(out[i]!=in[i]){
        printf("NO");
        return 0;
    }
    for(int i=1;i<=n;i++) if(head[i]){
        dfs(i);
        break;
    }
    if(tot!=m){
        printf("NO");
        return 0;
    }
    puts("YES");
    if(f==2) for(int i=tot;i>=1;i--) write(ans[i]),printf(" ");
    if(f==1) for(int i=tot;i>=1;i--){
        if(ans[i]%2) write((ans[i]+1)/2),printf(" ");
        else write(ans[i]/(-2)),printf(" ");
    }
    return 0;
}

 

posted @ 2018-10-23 15:32  Bruce--Wang  阅读(192)  评论(1编辑  收藏  举报