POJ 1679 The Unique MST (次小生成樹)

題目類型  次小生成樹

題目意思
給出 n 個點 m 條邊問最小生成樹是否唯一 (n <= 100)

解題方法
先用kruscal算法求出最小生成樹和構成最小生成樹的邊 然後對於這棵最小生成樹用 dfs 求出任兩點間路徑上最長的一條邊是多少
然後枚舉剛纔後面沒用過的邊 (u, v) , 新的生成樹的最小花費是 w(u,v) - maxlen[u][v] (即現在枚舉的邊的權值 - 最小生成樹上u,v間路徑上最長的一條邊)

參考代碼 - 有疑問的地方在下方留言 看到會盡快回復的
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>

using namespace std;

const int maxn = 100+10;

vector<int>E[maxn], W[maxn];
int fa[maxn];
int maxlen[maxn][maxn];
int nodepre[maxn], npre;

struct Edge {
	int u, v, w;
	bool operator < (const Edge & rhs) const {
		return w < rhs.w;
	}
}e[maxn*maxn];

int find(int x) {
	return fa[x] == x ? x : find(fa[x]);
}

void dfs(int u, int fa) { // nodepre 保存前面訪問過的點,對於邊(u,v)-> maxlen[pre][v] = max(maxlen[pre][v], W[u][i]);
	nodepre[npre++] = u;
	for( int i=0; i<E[u].size(); i++ ) {
		int v = E[u][i];
		if(v == fa) continue;
		maxlen[u][v] = maxlen[v][u] = W[u][i];
		for( int j=0; j<npre; j++ ) {
			int pre = nodepre[j];
			maxlen[pre][v] = max(maxlen[pre][u], W[u][i]);
			maxlen[v][pre] = maxlen[pre][v];
		}
		dfs(v, u);
	}
}

int main() {
	freopen("in", "r", stdin);
	int t;
	scanf("%d", &t);
	while(t--) {
		int n, m;
		scanf("%d%d", &n, &m);
		for( int i=0; i<m; i++ ) {
			scanf("%d%d%d", &e[i].u, &e[i].v, &e[i].w);
		}
		sort(e, e + m);
		for( int i=1; i<=n; i++ ) E[i].clear(), W[i].clear();
		for( int i=1; i<=n; i++ ) fa[i] = i;
		int tn = n, ti;
		int cost = 0;
		for( int i=0; i<m; i++ ) { // kruscal 算法
			int u = e[i].u, v = e[i].v, w = e[i].w;
			int x = find(u);
			int y = find(v);
			if(x != y) {
				fa[x] = y;
				E[u].push_back(v); W[u].push_back(w);
				E[v].push_back(u); W[v].push_back(w);
				tn--;
				cost += w;
				if(tn == 1) {
					ti = i+1;
					break;
				}
			}
		}
		npre = 0;
		for( int i=1; i<=n; i++ ) for( int j=1; j<=n; j++ ) maxlen[i][j] = 0;
		dfs(1, -1); // 求最小生成樹上任兩個間路徑最長的邊
		bool flag = true;
		for( int i=ti; i<m; i++ ) { // 枚舉後面沒用過的邊
			int u = e[i].u, v = e[i].v, w = e[i].w;
			if(cost == cost + w - maxlen[u][v]) { // 如果相等說明最小生成樹不唯一
				flag = false;
				break;
			}
		}
		if(flag) printf("%d\n", cost);
		else printf("Not Unique!\n");
	}
	return 0;
}
發佈了86 篇原創文章 · 獲贊 1 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章