做题记录整理图论/基环树/dfs P5022 [NOIP2018 提高组] 旅行(2022/10/19)
P5022 [NOIP2018 提高组] 旅行
其实部分分的做法(就是是树的时候)是很显然的,从1开始走,直接对每个点的所有出去的点排成升序,然后每次都走第一个点,出来的就是最小字典序了
然后基环树就只是枚举每一条边,然后切断他,再像之前一样做就得了。。。
#include<bits/stdc++.h>
#define for1(i,a,b) for(int i = a;i<=b;i++)
#define ll long long
#define mp(a,b) make_pair(a,b)
using namespace std;
vector<int> a[5010];
int n,m;
int dis[5010],ans[5010],cnt;
int vis[5010];
int du,dv;
struct node{
	int from,to;
}e[5010];
void dfs1(int u,int fa)
{
	if(vis[u])
		return ;
	vis[u]=1;
	dis[++cnt]=u;
	for1(i,0,a[u].size()-1) 
	{
		int v=a[u][i];
		if(v==fa)
			continue ;
		if((u==du&&v==dv)||(u==dv&&v==du))
			continue ;
		dfs1(v,u);
	}
}
void dfs2(int u,int fa) 
{
	if(vis[u]) return ;
	vis[u]=1;
	ans[++cnt]=u;
	for1(i,0,a[u].size()-1) 
	{
		int v=a[u][i];
		if(v==fa) continue ;
		dfs2(v,u);
	}
}
int check() 
{
	for1(i,1,n) 
	{
		if(dis[i]<ans[i]) 
		     return 1;
		else if(dis[i]>ans[i])
			return 0;
	}
	return 0;
}
int main() 
{
	scanf("%d%d",&n,&m);
	int x,y;
	for1(i,1,m) 
	{
		scanf("%d%d",&x,&y);
		a[x].push_back(y);
		a[y].push_back(x);
		e[i].from=x;
		e[i].to=y;
	}
	for1(i,1,n) sort(a[i].begin(),a[i].end());
	if(m==n)
	 {
		int kg=1;
		for1(i,1,m)
		{
			du=e[i].from,dv=e[i].to;
			memset(vis,0,sizeof(vis));
			cnt=0;
			dfs1(1,0);
			if(cnt<n) continue ;
			if(kg) 
			{
				for1(i,1,n) ans[i]=dis[i];
				kg=0;
			}
			if(check())
				for1(i,1,n) ans[i]=dis[i];
		}
		for1(i,1,n) printf("%d ",ans[i]);
	} 
	else 
	{
		dfs2(1,0);
		for1(i,1,n) printf("%d ",ans[i]);
	}
	return 0;
}

 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号