NOIP2018 D2T1 旅行 枚舉暴力+dfs

題目描述
小 Y 是一個愛好旅行的 OIer。她來到 X 國,打算將各個城市都玩一遍。

小Y瞭解到, X國的 n 個城市之間有 m 條雙向道路。每條雙向道路連接兩個城市。 不存在兩條連接同一對城市的道路,也不存在一條連接一個城市和它本身的道路。並且, 從任意一個城市出發,通過這些道路都可以到達任意一個其他城市。小 Y 只能通過這些 道路從一個城市前往另一個城市。

小 Y 的旅行方案是這樣的:任意選定一個城市作爲起點,然後從起點開始,每次可 以選擇一條與當前城市相連的道路,走向一個沒有去過的城市,或者沿着第一次訪問該 城市時經過的道路後退到上一個城市。當小 Y 回到起點時,她可以選擇結束這次旅行或 繼續旅行。需要注意的是,小 Y 要求在旅行方案中,每個城市都被訪問到。

爲了讓自己的旅行更有意義,小 Y 決定在每到達一個新的城市(包括起點)時,將 它的編號記錄下來。她知道這樣會形成一個長度爲 n 的序列。她希望這個序列的字典序 最小,你能幫幫她嗎? 對於兩個長度均爲 n 的序列 A 和 B,當且僅當存在一個正整數 x,滿足以下條件時, 我們說序列 A 的字典序小於 B。

對於任意正整數1≤i<x,序列 A 的第 i 個元素 A_i和序列 B 的第 i 個元素 B_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 。

對於不同的測試點, 我們約定數據的規模如下:

在這裏插入圖片描述

解法:枚舉暴力刪邊

  • 對於一個環,我們可以刪除這條邊,這樣就仍然可以用dfs了
  • 我們在刪邊的時候,同時判斷這種情況是否可行和是否是最優解

AC代碼

#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
#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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章