题意:
给定一张无向图,如果存在唯一的一个最小生成树,则输出大小,如果不存在,则输出 Not Unique!
思路:
1. 求其最小生成树,对于树上的每 2 个节点 u, v,如果边 (u, v) 不在树上,则补全,成为一个环,然后删除这个环中除了 (u, v) 之外最大的边
2. 如果此时树的大小仍为最小生成树的大小,则最小生成树不唯一。
3. dp[i, j] 代表生成树上两个节点 (i, j) 之间,最大的边的值。此时利用到了动态规划的思想求解。
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int MAXN = 110;
const int INFS = 0x3FFFFFFF;
int d[MAXN], p[MAXN], map[MAXN][MAXN], dp[MAXN][MAXN];
bool vis[MAXN];
int prim(int n) {
int ans = 0;
for (int i = 1; i <= n; i++)
d[i] = map[1][i], p[i] = 1;
memset(dp, 0, sizeof(dp));
memset(vis, false, sizeof(vis));
vector<int> inq;
vis[1] = true; inq.push_back(1);
for (int k = 1; k < n; k++) {
int j, temp = INFS;
for (int i = 1; i <= n; i++) {
if (!vis[i] && d[i] < temp)
j = i, temp = d[i];
}
vis[j] = true; ans += temp;
for (int i = 0; i < inq.size(); i++)
dp[j][inq[i]] = dp[inq[i]][j] = max(temp, dp[inq[i]][p[j]]);
inq.push_back(j);
for (int i = 1; i <= n; i++) {
if (!vis[i] && d[i] > map[i][j])
d[i] = map[i][j], p[i] = j;
}
}
return ans;
}
int main() {
int cases;
scanf("%d", &cases);
while (cases--) {
int n, m;
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
map[i][j] = (i == j) ? 0 : INFS;
for (int i = 0; i < m; i++) {
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
map[a][b] = map[b][a] = c;
}
int ans = prim(n);
int cflag = INFS;
for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++)
if (i != j && map[i][j] != INFS && p[i] != j && p[j] != i)
cflag = min(cflag, map[i][j] - dp[i][j]);
if (cflag == 0)
printf("Not Unique!\n");
else
printf("%d\n", ans);
}
return 0;
}