P7771 【模板】欧拉路径

欧拉路径:图G中的一条路径,能够通过图中的每一条边,并且每条边仅通过一次。

欧拉回路:欧拉回路是指起点和终点相同的欧拉路。

对于无向图,所有边都是连通的

(1)存在欧拉路径的充分必要条件:度数为奇数的点只能是0个或者2个

(2)存在欧拉回路的充分必要条件:度数为奇数的只能是0个

2对于有向图,所有边都是连通的 (1)存在欧拉路径的充分必要条件:要么所有点的出度均等于入度,
要么除了两个点之外,其余所有点的出度等于入度,剩余的两个点:一个满足出度比入度多1(起点),另一个满足入度比出度多1(终点)

(2)存在欧拉回路的充分必要条件:所有点的出度均等于入度

【模板】欧拉路径

题目描述

求有向图字典序最小的欧拉路径。

输入格式

第一行两个整数 n , m n,m n,m 表示有向图的点数和边数。

接下来 m m m 行每行两个整数 u , v u,v u,v 表示存在一条 u → v u\to v uv 的有向边。

输出格式

如果不存在欧拉路径,输出一行 No

否则输出一行 m + 1 m+1 m+1 个数字,表示字典序最小的欧拉路径。

样例 #1

样例输入 #1

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

样例输出 #1

1 2 1 3 3 4 2

样例 #2

样例输入 #2

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

样例输出 #2

1 2 3 4 3 5

样例 #3

样例输入 #3

4 3
1 2
1 3
1 4

样例输出 #3

No

提示

对于 50 % 50\% 50% 的数据, n , m ≤ 1 0 3 n,m\leq 10^3 n,m103

对于 100 % 100\% 100% 的数据, 1 ≤ u , v ≤ n ≤ 1 0 5 1\leq u,v\leq n\leq 10^5 1u,vn105 m ≤ 2 × 1 0 5 m\leq 2\times 10^5 m2×105

保证将有向边视为无向边后图连通。

数据生成器

#include<bits/stdc++.h>
using namespace std;
const int N=100010;
int n,m,start=1;
int ind[N],outd[N],p[N];
vector<int>vec[N];
stack<int>st;
 
void dfs(int now)
{
	for(int i=p[now];p[now]<vec[now].size();i++)
	{
		p[now]++;
		//cout<<"p[now]:"<<p[now]<<' '<<vec[now].size()<<endl;
		dfs(vec[now][i]);
	}
	st.push(now);
}
int main()
{
	cin>>n>>m;
	for(int i=0;i<m;i++)
	{
		int from,to;
		scanf("%d%d",&from,&to);
		vec[from].push_back(to);
		ind[to]++;
		outd[from]++;
	}
	int flag=0;
	for(int i=1;i<=n;i++)
	{
		sort(vec[i].begin(),vec[i].end());
		//cout<<i<<' '<<ind[i]<<' '<<outd[i]<<endl;
		if(ind[i]==outd[i]) continue;
		//cout<<i<<' '<<ind[i]<<' '<<outd[i]<<endl;
		else if(ind[i]==outd[i]+1) flag++;
		else if(ind[i]==outd[i]-1) start=i,flag--;	
		else
		{
			cout<<"No";
			return 0;
		}
	}
	if(flag!=0)
	{
		cout<<"No";
		return 0;
	}
	dfs(start);
	while(st.size())
		cout<<st.top()<<' ',st.pop();
	return 0;
}
3 3
1 2
1 3
3 1
1 3 1 2

可以hack掉

#include<bits/stdc++.h>
using namespace std;
const int N=100010;
int n,m,start;
int ind[N],outd[N],p[N];
vector<int>vec[N];

void dfs(int now)
{
	cout<<now<<' ';
	for(int i=p[now];p[now]<vec[now].size();i++)
	{
		p[now]++;
		//cout<<"p[now]:"<<p[now]<<' '<<vec[now].size()<<endl;
		dfs(vec[now][i]);
	}
}
int main()
{
	cin>>n>>m;
	for(int i=0;i<m;i++)
	{
		int from,to;
		scanf("%d%d",&from,&to);
		vec[from].push_back(to);
		ind[to]++;
		outd[from]++;
	}
	int flag=0;
	for(int i=1;i<=n;i++)
	{
		sort(vec[i].begin(),vec[i].end());
		//cout<<i<<' '<<ind[i]<<' '<<outd[i]<<endl;
		if(ind[i]==outd[i]) continue;
		//cout<<i<<' '<<ind[i]<<' '<<outd[i]<<endl;
		else if(ind[i]==outd[i]+1) flag++;
		else if(ind[i]==outd[i]-1) start=i,flag--;	
		else
		{
			cout<<"No";
			return 0;
		}
	}
	if(flag!=0)
	{
		cout<<"No";
		return 0;
	}
	dfs(start);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

春弦_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值