uoj117 欧拉回路
题目描述:
有一天一位灵魂画师画了一张图,现在要你找出欧拉回路,即在图中找一个环使得每条边都在环上出现恰好一次。
一共两个子任务:
-
这张图是无向图。(50 分)
-
这张图是有向图。(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 n1≤vi?,ui?≤n。
-
如果 t=1t = 1t=1 则表示 viv_ivi? 到 uiu_iui? 有一条无向边。
-
如果 t=2t = 2t=2 则表示 viv_ivi? 到 uiu_iui? 有一条有向边。
图中可能有重边也可能有自环。
输出格式:
如果不可以一笔画,输出一行 NO
。
否则,输出一行 YES
,接下来一行输出一组方案。
-
如果 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?。
-
如果 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; }