1. 程式人生 > >CCF 習題 201512-4 送貨 (並查集 + DFS 找尤拉道路)

CCF 習題 201512-4 送貨 (並查集 + DFS 找尤拉道路)

大體題意:

要求從1號出發,一筆畫經過所有的路,問是否有解,並列印字典序最小的解?

思路:

顯然是無向圖的尤拉道路!

先判連通,直接用並查集了,不連通直接-1了

連通的話,在看看每個點的度數,當奇點的個數不是0  並且不是2  肯定是-1

如果是2  的話,1號結點是偶數度數的話也是-1

否則我們就可以從1號結點直接dfs找路了!

注意:

不能再dfs之前就輸出路徑,這樣是不對的 = =  這樣只得了20分!

因為這個點可能不合適,因此我們要用的stack 最後輸出stack即可!

詳細見程式碼:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define mr make_pair
#include<stack> 
using namespace std;
const int maxn = 10001;
bool g[maxn][maxn];
int n,m;
int num[10001];
bool vis[maxn][maxn];
vector<int>G[maxn];
int fa[maxn];
stack<int>sk;
int find(int x){
	return fa[x] == x ? fa[x] : fa[x] = find(fa[x]);
}
void add(int x,int y){
	int xx = find(x);
	int yy = find(y);
	if (xx != yy)fa[yy] = xx;
}
void dfs(int k){
	int len = G[k].size();
	for (int i = 0; i < len; ++i){
		int t = G[k][i];
		if (!vis[k][t]){
			vis[k][t] = vis[t][k] = 1;
			dfs(t);
			sk.push(t);
		}
	}
	
}
int main(){
	scanf("%d %d", &n, &m);
	for (int i = 0; i <= n; ++i)fa[i] = i;
	for (int i = 0; i < m ;++i){
		int u,v;
		scanf("%d %d",&u,&v);
		add(u,v);
		G[u].push_back(v);
		G[v].push_back(u);
		num[u]++;
		num[v]++;
	}
	for (int i = 1; i <= n; ++i)sort(G[i].begin(),G[i].end());
	bool GO = 1;
	int t1 = find(1);
	for (int i = 1; i <= n; ++i){
		if (find(i) != t1){
			GO = 0;
			break;
		}
	}
	if (!GO)return 0 * puts("-1");
	int sum = 0;
	for (int i = 1; i <= n; ++i)if (num[i] & 1)++sum;
	if (sum != 0 && sum != 2)return 0 * puts("-1");
	if (sum == 2 && (num[1] & 1) == 0) return 0 * puts("-1");
	printf("1");
	dfs(1);
	while(!sk.empty()){
		printf(" %d",sk.top());
		sk.pop();
	}
	puts("");
	return 0;
}

問題描述
試題編號: 201512-4
試題名稱: 送貨
時間限制: 1.0s
記憶體限制: 256.0MB
問題描述: 問題描述   為了增加公司收入,F公司新開設了物流業務。由於F公司在業界的良好口碑,物流業務一開通即受到了消費者的歡迎,物流業務馬上遍及了城市的每條街道。然而,F公司現在只安排了小明一個人負責所有街道的服務。
  任務雖然繁重,但是小明有足夠的信心,他拿到了城市的地圖,準備研究最好的方案。城市中有n個交叉路口,m條街道連線在這些交叉路口之間,每條街道的首尾都正好連線著一個交叉路口。除開街道的首尾端點,街道不會在其他位置與其他街道相交。每個交叉路口都至少連線著一條街道,有的交叉路口可能只連線著一條或兩條街道。
  小明希望設計一個方案,從編號為1的交叉路口出發,每次必須沿街道去往街道另一端的路口,再從新的路口出發去往下一個路口,直到所有的街道都經過了正好一次。 輸入格式   輸入的第一行包含兩個整數n, m,表示交叉路口的數量和街道的數量,交叉路口從1到n標號。
  接下來m行,每行兩個整數a, b,表示和標號為a的交叉路口和標號為b的交叉路口之間有一條街道,街道是雙向的,小明可以從任意一端走向另一端。兩個路口之間最多有一條街道。 輸出格式   如果小明可以經過每條街道正好一次,則輸出一行包含m+1個整數p1
, p2, p3, ..., pm+1,表示小明經過的路口的順序,相鄰兩個整數之間用一個空格分隔。如果有多種方案滿足條件,則輸出字典序最小的一種方案,即首先保證p1最小,p1最小的前提下再保證p2最小,依此類推。
  如果不存在方案使得小明經過每條街道正好一次,則輸出一個整數-1。 樣例輸入 4 5
1 2
1 3
1 4
2 4
3 4 樣例輸出 1 2 4 1 3 4 樣例說明   城市的地圖和小明的路徑如下圖所示。
樣例輸入 4 6
1 2
1 3
1 4
2 4
3 4
2 3 樣例輸出 -1 樣例說明   城市的地圖如下圖所示,不存在滿足條件的路徑。
評測用例規模與約定   前30%的評測用例滿足:1 ≤ n ≤ 10, n-1 ≤ m ≤ 20。
  前50%的評測用例滿足:1 ≤ n ≤ 100, n-1 ≤ m ≤ 10000。
  所有評測用例滿足:1 ≤ n ≤ 10000,n-1 ≤ m ≤ 100000。