loj10105
loj10105
1 题目描述
有一天一位灵魂画师画了一张图,现在要你找出欧拉回路,即在图中找一个环使得每条边都在环上出现恰好一次。
一共两个子任务:
- 这张图是无向图。50( 分)
- 这张图是有向图。50( 分)
2 分析
这个题目就是欧拉回路的模板,但是被恶心到了,恶心的是只能算一个环,这个图原本可能还是不连通的。 另外,本题会有很多自环,也要优化一下,否则会超时。
3 代码
#pragma comment(linker, "/STACK:102400000,102400000")//手动开大栈区
#include<bits/stdc++.h>
using namespace std;
int const N=4e5+10;
int n,m,cnt,h[N],st[N<<1],top,in[N],out[N],vis[N<<1],f[N],us[N<<1],num[N];
vector<int> a[N],c[N],b[N];
void dfs(int x,int lm){
while (b[x].size()){
int y=b[x][b[x].size()-1];
int t=c[x][b[x].size()-1];
b[x].pop_back();
c[x].pop_back();
if(y<lm) continue;
if(!vis[abs(y)]){
vis[abs(y)]=1;
dfs(t,lm);
st[++top]=y;
}
}
}
int find(int x){
return x==f[x]? x:f[x]=find(f[x]);
}
int main(){
int t;
scanf("%d",&t);
cnt=top=0;
memset(h,0,sizeof(h));
memset(vis,0,sizeof(vis));
memset(in,0,sizeof(in));
memset(out,0,sizeof(out));
for(int i=1;i<=n;i++)
a[i].clear();
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) f[i]=i;
for(int i=1;i<=m;i++){
int x,y;
scanf("%d%d",&x,&y);
c[x].push_back(y);
c[y].push_back(x);
b[x].push_back(i);
b[y].push_back(-i);
f[find(x)]=find(y);
}
for(int i=1;i<=n;i++)
a[find(i)].push_back(i);
int check=0,ot=0;
for(int i=1;i<=n;i++)
{
if(a[i].size()==0) continue;
int num=0,nd,sum=0;
for(int j=0;j<a[i].size();j++){
int x=a[i][j];
nd=x;
sum+=b[x].size();
for(int k=0;k<c[x].size();k++){
int v=c[x][k];
int c=abs(b[x][k]);
if(t==2 && b[x][k]<0) continue;
if(us[c]) continue;
us[c]=1;
if(t==1) in[x]++,in[v]++;
else out[x]++,in[v]++;
}
}
for(int j=0;j<a[i].size();j++){
int x=a[i][j];
if(t==1){
if(in[x]%2==1)
num++;
}else {
if(in[x]!=out[x])
num++;
}
}
if(t==1){
if(num==0)
{
if(sum)
dfs(nd,-10000000),ot++;
}
else check=1;
}else {
if(num==0)
{
if(sum)
dfs(nd,0),ot++;
}
else check=1;
}
}
if(check || ot>1) printf("NO\n");
else {
printf("YES\n");
for(int i=top;i>=1;i--) printf("%d ",st[i]);
}
return 0;
}