uoj117 欧拉回路


题目描述:

有一天一位灵魂画师画了一张图,现在要你找出欧拉回路,即在图中找一个环使得每条边都在环上出现恰好一次。

一共两个子任务:

  1. 这张图是无向图。(50 分)

  2. 这张图是有向图。(50 分)

输入格式:

第一行一个整数 ttt,表示子任务编号。t∈{1,2}t \in \{1, 2\}t{1,2},如果 t=1t = 1t=1 则表示处理无向图的情况,如果 t=2t = 2t=2 则表示处理有向图的情况。

第二行两个整数 n,mn, mn,m,表示图的结点数和边数。

接下来 mmm 行中,第 iii 行两个整数 vi,uiv_i, u_ivi?,ui?,表示第 iii 条边(从 111 开始编号)。保证 1≤vi,ui≤n1 \leq v_i, u_i \leq n1vi?,ui?n。

  1. 如果 t=1t = 1t=1 则表示 viv_ivi? 到 uiu_iui? 有一条无向边。

  2. 如果 t=2t = 2t=2 则表示 viv_ivi? 到 uiu_iui? 有一条有向边。

图中可能有重边也可能有自环。

输出格式:

如果不可以一笔画,输出一行 NO

否则,输出一行 YES,接下来一行输出一组方案。

  1. 如果 t=1t = 1t=1,输出 mmm 个整数 p1,p2,…,pmp_1, p_2, \dots, p_mp1?,p2?,,pm?。令 e=∣pi∣e = \lvert p_i \rverte=pi?∣,那么 eee 表示经过的第 iii 条边的编号。如果 pip_ipi? 为正数表示从 vev_eve? 走到 ueu_eue?,否则表示从 ueu_eue? 走到 vev_eve?

  2. 如果 t=2t = 2t=2,输出 mmm 个整数 p1,p2,…,pmp_1, p_2, \dots, p_mp1?,p2?,,pm?。其中 pip_ipi? 表示经过的第 iii 条边的编号。

根据题目名称我们得知这道题是一道判断欧拉回路的板子题,那么怎么判欧拉回路?

如果这个图是无向图,那么对于每个点,它的度都要是偶数。然后路径就是在这个图上随便找一个点开始,随便跑,只要不重复就行。

如果这个图是有向图,那么对于每个店,它的入度和出度要一样。然后从图上一个有出边的点遍历。

就是要注意无向图时,如果a->b这条边跑过了,那么b->a这条边也要标记,而且存边时也要注意细节。

#include
#include
#include
#include
#include
#include
#define in(a) a=read()
#define REP(i,k,n) for(int i=k;i<=n;i++)
#define MAXN 2000010
using namespace std;
inline int read(){
    int x=0,t=1,c;
    while(!isdigit(c=getchar())) if(c=='-') t=-1;
    while(isdigit(c)) x=x*10+c-'0',c=getchar();
    return x*t;
}
int t,n,m;
int total=0,head[MAXN],to[MAXN<<1],nxt[MAXN<<1];
int ans[MAXN<<1],ind,vis[MAXN<<1];
int In[MAXN],out[MAXN],du[MAXN];
inline void adl(int a,int b){
    total++;
    to[total]=b;
    nxt[total]=head[a];
    head[a]=total;
    return ;
}
inline void dfs(int u){
    for(int &e=head[u];e;e=nxt[e])
        if(!vis[e]){
            int k=e;
            vis[e]=1;
            if(t==1){//标记细节
                if(e%2)  vis[e+1]=1;
                else  vis[e-1]=1;
            }
            dfs(to[e]);
            ans[++ind]=k;
        }
    return ;
}
int main(){
    in(t),in(n),in(m);
    int a,b;
    if(t==1){
        REP(i,1,m)
            in(a),in(b),du[a]++,du[b]++,adl(a,b),adl(b,a);
        REP(i,1,n)
            if(du[i]%2){
                cout<<"NO"<<endl;
                return 0;
            }
    }
    if(t==2){
        REP(i,1,m)
            in(a),in(b),In[b]++,out[a]++,adl(a,b);
        REP(i,1,n)
            if(In[i]!=out[i]){
                cout<<"NO"<<endl;
                return 0;
            }
    }
    REP(i,1,n)
        if(head[i]){
            dfs(i);
            break;
        }
    if(ind!=m){
           cout<<"NO";
           return 0;
    }
    cout<<"YES"<<endl;
    if(t==2){
        REP(i,0,ind-1)
            printf("%d ",ans[ind-i]);
        return 0;
    }
    REP(i,0,ind-1){
         if(ans[ind-i]%2)  printf("%d ",(ans[ind-i]+1)/2);//输出细节
         else  printf("%d ",ans[ind-i]/(-2));
     }
    return 0;
}