P7771 【模板】欧拉路径
题目描述
求有向图字典序最小的欧拉路径。
输入格式
第一行两个整数 n,mn,m 表示有向图的点数和边数。
接下来 mm 行每行两个整数 u,vu,v 表示存在一条 u\to vu→v 的有向边。
输出格式
如果不存在欧拉路径,输出一行 No。
否则输出一行 m+1m+1 个数字,表示字典序最小的欧拉路径。
算法内容:
先判断是否符合构成欧拉回路的条件,若符合,则开始搜索
从出度比入度大1的点开始,若遍历到某个点没有边了,则该点一定是终点。因为欧拉图中入度比出度大1的点一定是终点
代码中st数组是防止超时的关键
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int n,m,u,v,f,deg[200010],st[200010];//st数组代表删除的边
struct node{
int id,vis;
friend bool operator<(const node&x,const node&y){
return x.id<y.id;
}
};
vector<node> g[200010];
stack<int> res;
void dfs(int x){
int l=g[x].size();
for(int i=0;i<l;i=max(i+1,st[x])){//直接令i等于st[x]可以防止重复遍历导致的超时
if(g[x][i].vis)continue;
g[x][i].vis=1;
st[x]=i+1;
dfs(g[x][i].id);
}
res.push(x);
}
int main(){
ios::sync_with_stdio(0);
cin>>n>>m;
for(int i=1;i<=m;i++){
cin>>u>>v;
g[u].push_back({v,0});
deg[u]--,deg[v]++;
}
int k1=0,k2=0,start=1;
for(int i=1;i<=n;i++){
if(deg[i]>1||deg[i]<-1){
cout<<"No\n";
return 0;
}
if(deg[i]==-1){
start=i;
k1++;
}
if(deg[i]==1){
k2++;
}
if(k1>1||k2>1){
cout<<"No\n";
return 0;
}
}
for(int i=1;i<=n;i++)sort(g[i].begin(),g[i].end());
dfs(start);
while(!res.empty())cout<<res.top()<<' ',res.pop();
return 0;
}