POJ1679 The Unique MST 题解 次小生成树 题解 Kruskal+暴力LCA解法(因为倍增不会写)
题目链接:http://poj.org/problem?id=1679
题目大意:
给你一个简单连通图,判断他的最小生成树是否唯一。
解题思路:
首先(我这里用Kruskal算法)求出它的最小生成树(以下简称MST)以及对应的边,然后构造出这棵MST。
然后我们枚举图上每一条不在此MST上的边,假设这条边的两个端点是 \(u\) 和 \(v\),边权为 \(w\) ,求MST上 \(u\) 到 \(v\) 的树链上的最大边的值是否等于 \(w\),如果等于 \(w\) 就说明 MST 不唯一。
这一部分可以用树上倍增算法解决,但是我暂时还不会写,所以我就暴力做了囧。
所以我这样写的时间复杂度是:
Kruskal算法的 \(O(m \log m)\) + 枚举每一条边+LCA的 \(O(mn)\) = \(O(m \log m + mn)\) 。
实现代码如下:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn = 110, maxm = 10010;
int T, n, m, f[maxn], p[maxn], pe[maxn], ans, dep[maxn];
struct Edge {
int u, v, w;
bool choose;
Edge () { choose = false; };
Edge (int _u, int _v, int _w) { u = _u; v = _v; w = _w; choose = false; }
} edge[maxm];
vector<Edge> g[maxn];
void init() {
ans = 0;
for (int i = 1; i <= n; i ++) {
g[i].clear();
f[i] = i;
}
}
int func_find(int x) {
if (x == f[x]) return x;
return f[x] = func_find(f[x]);
}
void func_union(int x, int y) {
int a = func_find(x), b = func_find(y);
f[a] = f[b] = f[x] = f[y] = min(a, b);
}
inline bool cmp(Edge a, Edge b) {
return a.w < b.w;
}
void kruskal() {
int cnt = 0;
sort(edge, edge+m, cmp);
for (int i = 0; i < m; i ++) {
int u = edge[i].u, v = edge[i].v, w = edge[i].w;
if (func_find(u) != func_find(v)) {
edge[i].choose = true;
func_union(u, v);
ans += w;
g[u].push_back(Edge(u, v, w));
g[v].push_back(Edge(v, u, w));
cnt ++;
if (cnt >= n-1) break;
}
}
}
void dfs(int u, int d) {
dep[u] = d;
int sz = g[u].size();
for (int i = 0; i < sz; i ++) {
int v = g[u][i].v, w = g[u][i].w;
if (v == p[u]) continue;
p[v] = u;
pe[v] = w;
dfs(v, d+1);
}
}
int find_chain(int u, int v) {
int maxw = 0;
while (u != v) {
if (dep[u] > dep[v]) {
maxw = max(maxw, pe[u]);
u = p[u];
}
else {
maxw = max(maxw, pe[v]);
v = p[v];
}
}
return maxw;
}
int main() {
scanf("%d", &T);
while (T --) {
scanf("%d%d", &n, &m);
init();
for (int i = 0; i < m; i ++)
scanf("%d%d%d", &edge[i].u, &edge[i].v, &edge[i].w);
kruskal();
dep[1] = 1;
dfs(1, 1);
bool is_unique = true;
for (int i = 0; i < m; i ++) {
if (!edge[i].choose) {
int u = edge[i].u, v = edge[i].v, w = edge[i].w;
if (find_chain(u, v) == w) {
is_unique = false;
break;
}
}
}
if (is_unique) printf("%d\n", ans);
else puts("Not Unique!");
}
return 0;
}