POJ - 1679 The Unique MST

题意:

给定一个有 n 个点的无向图,判断最小生成树是否唯一。

链接:

https://vjudge.net/problem/POJ-1679

解题思路:

考虑在 Kruskal 算法基础上进行判断。排序后,对于一段权值相同的边,先判断有多少条可以加入最小生成树,统计最终实际加入几条,若两者不相等,说明有环,且环包含至少两条相同权值的边,则最小生成树不唯一。

参考代码:

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
#define pb push_back
#define sz(a) ((int)a.size())
#define mem(a, b) memset(a, b, sizeof a)
#define lson (rt << 1)
#define rson (rt << 1 | 1)
#define gmid (l + r >> 1)
const int maxn = 1e5 + 5;
const int maxm = 6e6 + 5;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;

struct Edge{
	int u, v, w;
	bool operator < (const Edge &o) const{
		return w < o.w;
	}
} ei[maxn];
int pre[maxn];
int n, m;

int fin(int x){

	return x == pre[x] ? x : pre[x] = fin(pre[x]);
}

int solve(){

	sort(ei + 1, ei + 1 + m);
	for(int i = 1; i <= n; ++i) pre[i] = i;
	int ret = 0, cnt = 1, cnt1 = 0, cnt2 = 0;
	for(int i = 1, j = 1; i <= m; ){

		cnt1 = cnt2 = 0;
		while(j <= m && ei[i].w == ei[j].w){

			if(fin(ei[j].u) != fin(ei[j].v)) ++cnt2;
			++j;
		}
		while(i < j){

			int x = fin(ei[i].u), y = fin(ei[i].v);
			if(x != y) pre[x] = y, ret += cnt < n ? ei[i].w : 0, ++cnt, ++cnt1;
			++i;
		}
		if(cnt1 != cnt2) return -1;
	}
	return ret;
}

int main(){

//	ios::sync_with_stdio(0); cin.tie(0);
	int t; scanf("%d", &t);
	while(t--){

		scanf("%d%d", &n, &m);
		for(int i = 1; i <= m; ++i){

			scanf("%d%d%d", &ei[i].u, &ei[i].v, &ei[i].w);
		}
		int ret = solve();
		if(ret == -1) printf("Not Unique!\n");
		else printf("%d\n", ret);
	}
	return 0;
}

 
此外,还可以通过求非严格次小生成树来判断唯一性。对于一条不在最小生成树上的边(u,v,w),贪心替换掉生成树上 u -> v 路径上最大权值边,所有替换情况取小即是非严格最小生成树。实现用倍增即可。
 

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
#define pb push_back
#define sz(a) ((int)a.size())
#define mem(a, b) memset(a, b, sizeof a)
#define lson (rt << 1)
#define rson (rt << 1 | 1)
#define gmid (l + r >> 1)
const int maxn = 1e5 + 5;
const int maxm = 6e6 + 5;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;

vector<pii> G[maxn];
struct Edge{
	int u, v, w;
	bool operator < (const Edge &o) const{
		return w < o.w;
	}
} ei[maxn];
int pre[maxn], dep[maxn], fa[maxn][21], mx[maxn][21];
int n, m, p;

int fin(int x){

	return x == pre[x] ? x : pre[x] = fin(pre[x]);
}

void dfs(int u, int f){

	fa[u][0] = f, dep[u] = dep[f] + 1;
	for(int i = 1; i <= 20; ++i){

		fa[u][i] = fa[fa[u][i - 1]][i - 1];
		mx[u][i] = max(mx[u][i - 1], mx[fa[u][i - 1]][i - 1]);
	}
	for(int i = 0; i < sz(G[u]); ++i){

		int v = G[u][i].second, w = G[u][i].first;
		if(v == f) continue;
		mx[v][0] = w;
		dfs(v, u);
	}
}

int getMax(int u, int v){

	if(dep[u] < dep[v]) swap(u, v);
	int ret = 0;
	for(int i = 20; i >= 0; --i){

		if(dep[fa[u][i]] >= dep[v]) ret = max(ret, mx[u][i]), u = fa[u][i];
	}
	if(u == v) return ret;
	for(int i = 20; i >= 0; --i){

		if(fa[u][i] != fa[v][i]){

			ret = max(ret, max(mx[u][i], mx[v][i]));
			u = fa[u][i], v = fa[v][i];
		}
	}
	return max(ret, max(mx[u][0], mx[v][0]));
}

int kruskal(){

	sort(ei + 1, ei + 1 + m);
	for(int i = 1; i <= n; ++i) pre[i] = i;
	for(int i = 1; i <= n; ++i) G[i].clear();
	int ret = 0, cnt = 1; p = 0;
	for(int i = 1; i <= m; ++i){

		int x = fin(ei[i].u), y = fin(ei[i].v);
		if(cnt < n && x != y){

			++cnt, ret += ei[i].w, pre[x] = y;
			G[ei[i].u].pb({ei[i].w, ei[i].v}), G[ei[i].v].pb({ei[i].w, ei[i].u});
		}
		else ei[++p] = ei[i];
	}
	return ret;
}

int main(){

//	ios::sync_with_stdio(0); cin.tie(0);
	int t; scanf("%d", &t);
	while(t--){

		scanf("%d%d", &n, &m);
		for(int i = 1; i <= m; ++i){

			scanf("%d%d%d", &ei[i].u, &ei[i].v, &ei[i].w);
		}
		int ret = kruskal(), ret2 = inf;
		dfs(1, 0);
		for(int i = 1; i <= p; ++i){

			int tmp = getMax(ei[i].u, ei[i].v);
			ret2 = min(ret2, ret + ei[i].w - tmp);
		}
		if(ret == ret2) printf("Not Unique!\n");
		else printf("%d\n", ret);
	}
	return 0;
}
发布了55 篇原创文章 · 获赞 0 · 访问量 1272

猜你喜欢

转载自blog.csdn.net/weixin_44059127/article/details/101313633
今日推荐