题意大概为找到一个字典序最小的欧拉道路/回路,不过数据范围给的异常的大,所以应该是要对做法有一些要求。
对于一条欧拉道路,需要有向图中存在且仅存在一对点,使得一个点的入读比出度大一(这个点即为最终到达的点),另一个点出度比入读大一(这个点即为初始点)。
对于一条欧拉回路,需要有向图中所有点的入读=出度。
当然,进行以上两个判定之前,还需要保证给出的图所有的边都联通(这一点可以用并查集解决)。
因此我们只需要判断这两个条件是否满足即可。
需要注意的是,在寻找路径的函数进行回溯的时候,如果使用打标记的方法判定某条边是否走过,其实在枚举的时候还是会枚举到,最后还是会TLE。所以可以对每个点用优先队列存储能到达的点,在寻找路径的时候以能到达的点从小到大的顺序进行搜索。
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<stack>
#include<vector>
#include<cmath>
#include<map>
#define LL long long
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=1e6+5;
inline void _read(int &x){
char t=getchar();bool sign=true;
while(t<'0'||t>'9')
{if(t=='-')sign=false;t=getchar();}
for(x=0;t>='0'&&t<='9';t=getchar())x=x*10+t-'0';
if(!sign)x=-x;
}
struct Edge{
int from,to;
bool operator <(const Edge& h)const{
return from==h.from?to>h.to:from>h.from;
}
}edges[maxn<<1],ans[maxn<<1];
int n,m,rd[maxn],cd[maxn],mark[maxn],fa[maxn],cnt,tot;
priority_queue<Edge>q[maxn];
int getfa(int x){return fa[x]==x?x:fa[x]=getfa(fa[x]);}
void euler(int u){
while(q[u].size()){
int v=q[u].top().to;q[u].pop();
euler(v);
ans[++tot]=(Edge){u,v};
}
}
int main(){
_read(n);_read(m);
for(int i=1;i<=n;i++)fa[i]=i;
int s=n;
for(int i=1;i<=m;i++){
int x,y;
_read(x);_read(y);
edges[i].from=x;
edges[i].to=y;
mark[x]=mark[y]=1;
rd[y]++,cd[x]++;
int fx=getfa(x),fy=getfa(y);
if(fx!=fy)fa[fx]=fy;
s=min(s,x);
}
int c1=0,c2=0;
for(int i=1;i<=n;i++)
if(mark[i]){
if(rd[i]==cd[i])continue;
else if(rd[i]==cd[i]+1)c1++;
else if(cd[i]==rd[i]+1)c2++,s=i;
else {
puts("What a shame!");
return 0;
}
}
int flag=0;
for(int i=1;i<=n;i++)
if(mark[i]&&getfa(i)==i)flag++;
if(((c1==c2&&c1==0)||(c1==c2&&c1==1))&&flag==1){
for(int i=1;i<=m;i++)q[edges[i].from].push((Edge){edges[i].from,edges[i].to});
euler(s);
for(int i=tot;i>=1;i--)
if(i==tot)printf("%d %d ",ans[i].from,ans[i].to);
else printf("%d ",ans[i].to);
}
else {
puts("What a shame!");
return 0;
}
}