NOIP2018 D2T1 旅行 枚举暴力+dfs

题目描述
小 Y 是一个爱好旅行的 OIer。她来到 X 国,打算将各个城市都玩一遍。

小Y了解到, X国的 n 个城市之间有 m 条双向道路。每条双向道路连接两个城市。 不存在两条连接同一对城市的道路,也不存在一条连接一个城市和它本身的道路。并且, 从任意一个城市出发,通过这些道路都可以到达任意一个其他城市。小 Y 只能通过这些 道路从一个城市前往另一个城市。

小 Y 的旅行方案是这样的:任意选定一个城市作为起点,然后从起点开始,每次可 以选择一条与当前城市相连的道路,走向一个没有去过的城市,或者沿着第一次访问该 城市时经过的道路后退到上一个城市。当小 Y 回到起点时,她可以选择结束这次旅行或 继续旅行。需要注意的是,小 Y 要求在旅行方案中,每个城市都被访问到。

为了让自己的旅行更有意义,小 Y 决定在每到达一个新的城市(包括起点)时,将 它的编号记录下来。她知道这样会形成一个长度为 n 的序列。她希望这个序列的字典序 最小,你能帮帮她吗? 对于两个长度均为 n 的序列 A 和 B,当且仅当存在一个正整数 x,满足以下条件时, 我们说序列 A 的字典序小于 B。

对于任意正整数1≤i 序列 A 的第 x 个元素的值小于序列 B 的第 x 个元素的值。
输入格式
输入文件共 m+1 行。第一行包含两个整数 n,m(m≤n),中间用一个空格分隔。

接下来 m 行,每行包含两个整数 u,v(1≤u,v≤n) ,表示编号为 u 和 v 的城市之 间有一条道路,两个整数之间用一个空格分隔。

输出格式
输出文件包含一行,n 个整数,表示字典序最小的序列。相邻两个整数之间用一个 空格分隔。

输入输出样例
输入 #1
6 5
1 3
2 3
2 5
3 4
4 6
输出 #1
1 3 2 5 4 6
输入 #2
6 6
1 3
2 3
2 5
3 4
4 5
4 6
输出 #2
1 3 2 4 5 6
说明/提示
【数据规模与约定】

对于100% 的数据和所有样例, 1≤n≤5000 且 m=n−1 或 m=n 。

对于不同的测试点, 我们约定数据的规模如下:

NOIP2018 D2T1 旅行 枚举暴力+dfs_第1张图片

解法:枚举暴力删边

  • 对于一个环,我们可以删除这条边,这样就仍然可以用dfs了
  • 我们在删边的时候,同时判断这种情况是否可行和是否是最优解

AC代码

#include
#include
#include
#include
#define si 5050
#define re register int
using namespace std;
struct edge {
	int nex,fro,to;
}e[si<<1];
int n,m,d,bx,by,cnt,k[si],ans[si],head[si];
vector<int> p[si]; bool v[si];
inline int read() {
	int x=0,cf=1;
	char ch=getchar();
	while(ch<'0'||ch>'9') {
		if(ch=='-') cf=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9') {
		x=(x<<3)+(x<<1)+(ch^48);
		ch=getchar();
	}
	return x*cf;
}
inline void add(int x,int y) {
	e[++cnt].to=y,e[cnt].fro=x,e[cnt].nex=head[x],head[x]=cnt;
}
inline void dfs(int x,int fa) {
	if(v[x]) return;
	v[x]=1,k[++d]=x;
	for(re i=0;i<p[x].size();i++) {
		int y=p[x][i]; if(y==fa) continue;
		if((x==bx&&y==by)||(y==bx&&x==by)) continue;//删边
		dfs(y,x);
	}
}
inline void change() {
	for(re i=1;i<=n;i++) ans[i]=k[i];
}
inline bool check() {
	for(re i=1;i<=n;i++) {
		if(k[i]>ans[i]) return false;
		else if(k[i]<ans[i]) return true;
	}
}
inline void fans(int x,int fa) {
	ans[++d]=x; 
	for(re i=0;i<p[x].size();i++) {
		int y=p[x][i];
		if(y==fa) continue;
		fans(y,x);
	}
}
int main() {
	n=read(),m=read();
	for(re i=1;i<=m;i++) {
		int x=read(),y=read();
		add(x,y),add(y,x);
		p[x].push_back(y);
		p[y].push_back(x);
	}
	for(re i=1;i<=n;i++) {
		sort(p[i].begin(),p[i].end());//寻找最优解
	}
	if(n==m) {
		for(re i=0;i<cnt;i+=2) {
			memset(v,false,sizeof(v));
			d=0,bx=e[i].fro,by=e[i].to;
			dfs(1,-1);
			if(d<n) continue;//这时候图不联通
			else if(!ans[1]) change();//如果还没有解,那么直接当作一个解
			else if(check()) change();
		}
		for(re i=1;i<=n;i++) {
			printf("%d ",ans[i]);
		}
		return 0;
	}
	fans(1,-1);
	for(re i=1;i<=n;i++) {
		printf("%d ",ans[i]);
	}
	return 0;
}

你可能感兴趣的:(dfs,枚举)