【基环树,Topsort】洛谷P5022 旅行

版权声明:虽然本蒟蒻很菜,但各位dalao转载请注明出处谢谢。 https://blog.csdn.net/xuxiayang/article/details/88067071

D e s c r i p t i o n Description

给定一棵树(或者是基环树),求从一点出发遍历所有点(可以重复经过且无向)的字典序最小的序列是什么?


S o l u t i o n Solution

对于树的情况,显然贪心即可,时间复杂度: O ( n l o g n ) O(nlogn) (排序的复杂度)

对于基环树的情况,暴力拆环找即可,时间复杂度 O ( n 2 ) O(n^2)

一些细节:

首先要对边排序呀,这样就可以比较方便的解决贪心的问题

然后找环用 t o p s o r t topsort

接下来就暴力拆边跑 d f s dfs


C o d e Code

#include<queue>
#include<cstdio>
#include<vector>
#include<cctype>
#include<cstring>
#include<algorithm>
using namespace std;int n,m,a[5001],len,t,ans[5001],x,y,rd[5001],root,fa;//a为当前遍历的集合,ans为最终答案,rd为入度,root为环上的任意一点
vector<int>g[5001];//邻接表数组,这里用vector是为了方便排序
inline long long read()
{
    char c;int d=1;long long f=0;
    while(c=getchar(),!isdigit(c))if(c==45)d=-1;f=(f<<3)+(f<<1)+c-48;
    while(c=getchar(),isdigit(c)) f=(f<<3)+(f<<1)+c-48;
    return d*f;
}
inline void dfs(int x,int fa,int nx,int ny)//当前遍历的点,上一次遍历的点,被删除的边连接的两个点
{
	a[++len]=x;
	for(register int i=0;i<g[x].size();i++)
	{
		int y=g[x][i];
		if(y==fa||x==nx&&y==ny||x==ny&&y==nx) continue;
		dfs(y,x,nx,ny);
	} 
}
inline bool comp()//比较当前情况是否最优
{
	if(len<n) return false;//没有搜到
	if(!ans[1]) return true;//第一次搜到
	for(register int i=1;i<=n;i++) if(a[i]!=ans[i]) return a[i]<ans[i];
	return false;
}
inline void topsort()//拓扑排序
{
    queue<int>q;
    int y,w;
    for(register int i=1;i<=n;i++) if(!--rd[i]) q.push(i);
    while(q.size())
    {
        int x=q.front();q.pop();
        for(register int i=0;i<g[x].size();i++) if(!--rd[y=g[x][i]]) q.push(y);
    }
    return;
}
signed main()
{
	n=read();m=read();
	for(register int i=1;i<=m;i++) rd[x=read()]++,rd[y=read()]++,g[x].push_back(y),g[y].push_back(x);//输入+初始化
	for(register int i=1;i<=n;i++) sort(g[i].begin(),g[i].end());//边排序
	if(m<n)//是一棵树
	{
		dfs(1,0,0,0);
		for(register int i=1;i<=n;i++) printf("%d ",a[i]);//暴力遍历然后输出
		return 0;
	}
	topsort();//拓扑排序
	for(register int i=1;i<=n;i++) if(rd[i]>0) {root=i;break;}//找到环上的点
	x=root;fa=0;
	do//遍历这个环
	{
		for(register int i=0;i<g[x].size();i++)
		if(rd[y=g[x][i]]>0&&y!=fa)
		{
			len=0;
			dfs(1,0,x,y);
			if(comp()) memcpy(ans,a,sizeof(a));
			fa=x;x=y;
			break;
		}
	}while(x!=root);//直到遍历完这个环
	for(register int i=1;i<=n;i++) printf("%d ",ans[i]);
}

猜你喜欢

转载自blog.csdn.net/xuxiayang/article/details/88067071