【UOJ 117】欧拉回路

【题目】

传送门

题目描述:

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

一共两个子任务:

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

输入格式:

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

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

接下来 m 行中,第 i 行两个整数 v_i,u_i,表示第 i 条边(从 1 开始编号)。保证 1 ≤ v_i,u_in

  1. 如果 t=1 则表示 v_i 到 u_i 有一条无向边。
  2. 如果 t=2 则表示 v_i 到 u_i 有一条有向边。

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

输出格式:

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

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

  1. 如果 t=1,输出 m 个整数 p_1,p_2,…,p_m。令 e=\left | p_i \right |,那么 e 表示经过的第 i 条边的编号。如果 p_i 为正数表示从 v_e 走到 u_e,否则表示从 u_e 走到 v_e
  2. 如果 t=2,输出 m 个整数 p_1,p_2,…,p_m。其中 p_i 表示经过的第 i 条边的编号。

样例数据:

【样例1】

输入

1
3 3
1 2
2 3
1 3

输出

YES
1 2 -3

【样例2】

输入

2
5 6
2 3
2 5
3 4
1 2
4 2
5 1

输出

YES
4 1 3 5 2 6

限制与约定:

本题有 SPJ

1 ≤ n ≤ 10^5,0 ≤ m ≤ 2\times 10^5

【分析】

今天终于学会欧拉回路了,开心

这道题就是欧拉回路的板题啦,并不难,就不做单独解释了

【代码】 

#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 100005
#define M 500005
#define wrong {printf("NO");return 0;}
using namespace std;
int n,m,t,size;
int in[N],out[N],ans[N];
int num=1,v[M],next[M],first[N];
bool vis[M];
void add(int x,int y)
{
	num++;
	next[num]=first[x];
	first[x]=num;
	v[num]=y;
}
void dfs(int x)
{
	for(int &i=first[x];i;i=next[i])
	{
		int j=v[i],flag=i%2;
		int e=(t==1?i/2:i-1);
		if(vis[e])  continue;
		vis[e]=true,dfs(j);
		if(t==1&&flag)  ans[++size]=-e;
		else  ans[++size]=e;
	}
}
int main()
{
	int x,y,i,j;
	scanf("%d%d%d",&t,&n,&m);
	for(i=1;i<=m;++i)
	{
		scanf("%d%d",&x,&y);
		add(x,y);out[x]++,in[y]++;
		if(t==1)  add(y,x);
	}
	for(i=1;i<=n;++i)
	{
		if(t==1&&(in[i]+out[i])%2)  wrong;
		if(t==2&&in[i]!=out[i])  wrong;
	}
	for(i=1;i<=n;++i)
	{
		if(first[i])
		{
			dfs(i);
			break;
		}
	}
	if(size!=m)  wrong;
	printf("YES\n");
	for(i=size;i>=1;--i)
	  printf("%d ",ans[i]);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/forever_dreams/article/details/82947879