试题描述
|
有一天一位灵魂画师画了一张图,现在要你找出欧拉回路,即在图中找一个环使得每条边都在环上出现恰好一次。
一共两个子任务: 这张图是无向图。 这张图是有向图。 |
输入
|
第一行一个整数 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; }