最小生成樹-Magicpig密室出逃(Kruskal+並查集)

Kruskal算法

Kruskal算法是按邊權從小到大依次加入邊,如果某次加邊產生了環(並查集判斷),就扔掉這條邊,直到加入了n-1條邊,即形成了一棵樹。

題目

在金字塔中有一個叫Room-of-No-Return 的大房間,非常不幸的是Magicpig現在被困在這個房間裏。房間的地板上有一些鉤子。在房間的牆上有一些古老的埃及文字:“如果你想逃離這裏,你必須用繩索連接所有這些鉤子,然後一個祕密的門將打開,你將獲得自由。如果你不能這樣做,你將永遠被困在這裏”。幸運的是Magicpig有一條長度爲L的繩索,他可以把它切成段,每段可以連接兩個鉤子,如果他能用這段繩子連接所有鉤子,並且連接的繩子不能出現環路,就可以成功逃脫!Kinfkong想知道他是否可以逃跑。

輸入格式:

輸入包含一個或多個數據集。在每個輸入數據集的第1行有兩個整數n和L,其中n是鉤子的數量,L是繩索的長度。接下來的n行包含鉤子的一系列座標,每個座標是一個非負整數對,並且每個整數小於32768,每對都用空格分隔(2<=n<=100,L<=32767)。鉤子的數量n 爲零表示輸入結束。

輸出格式:

對於每個數據集,如果Magicpig可以逃脫,打印一個字符串”Success!”,否則打印“Poor magicpig!”.

輸入樣例:

2 1
0 0
1 1 
2 2
0 0
1 1
0

輸出樣例:

Poor magicpig!
Success!

分析

首先準備工作把題目讀入的座標,構建成完全連通圖,得到邊(兩點距離公式)。
然後就是套用Krusakal算法,先對邊排序,遍歷每次選最小的邊,然後用並查集判斷它的兩個端點是否在一個集合,不是的話則加入該邊,更新花費和並操作。
最後返回花費和繩索長度比較即可。

代碼

#include<bits/stdc++.h>
using namespace std;
#define maxn 102
int n, m;
int cnt;//邊數
int root[maxn];
struct node {
	int x, y;//座標
	int idx;//下標
}points[maxn];
struct node2 {
	int u, v;//端點
	double cost;//權值
}edge[maxn*maxn];
bool cmp(node2 a, node2 b) {
	return a.cost < b.cost;
}
int Find(int x) {
	return root[x] == x ? x : root[x] = Find(root[x]);
}
double Kruskal() {
	for (int i = 0; i <= n; i++)
		root[i] = i;
	sort(edge + 1, edge + cnt, cmp);
	double ans = 0;
	for (int i = 1; i <= cnt; i++) {
		int u = Find(edge[i].u);
		int v = Find(edge[i].v);
		if (u != v) {
			root[u] = v;//Union
			ans += edge[i].cost;
		}
	}
	//判斷非連通圖
	return ans;
}
int main() {
	while (~scanf("%d", &n) && n != 0) {
		scanf("%d", &m);
		for (int i = 1; i <= n; i++) {
			scanf("%d%d", &points[i].x, &points[i].y);
			points[i].idx = i;
		}
		cnt = 1;
		for (int i = 1; i <= n; i++) {
			for (int j = i + 1; j <= n; j++) {
				edge[cnt].u = points[i].idx;
				edge[cnt].v = points[j].idx;
				double cost = pow(points[i].x - points[j].x, 2);
				cost += pow(points[i].y - points[j].y, 2);
				cost = sqrt(cost);
				edge[cnt].cost = cost;
				cnt++;
			}
		}
		double ans = Kruskal();
		if (ans > m)printf("Poor magicpig!\n");
		else printf("Success!\n");
	}
	return 0;
}

小結

  1. 一般Kruskal算法最後還要判斷構建出來的圖是否爲連通圖,由於本題把座標兩兩求邊得到完全連通圖便省略。
  2. 圖的存儲問題:若鄰接矩陣超限,考慮鄰接表(vector實現)。

你的點贊將會是我最大的動力

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章