loj10105

loj10105

1 题目描述

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

一共两个子任务:

  1. 这张图是无向图。50( 分)
  2. 这张图是有向图。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; 
}
posted @ 2020-08-18 14:38  zjxxcn  阅读(164)  评论(0编辑  收藏  举报