题目链接:1679:The Unique MST
分析:
- 参考了这篇文章,该文章采用邻接矩阵,介绍了Kruskal和Prim两种方法,我们采用邻接表+Prim
- 核心思想:
- 在最小生成树上添加一条边,必然成环
- 从环中删除一条边(不是新加进来的),新的总权值 ≥ \ge ≥旧的总权值
- 如果相等则说明最小生成树不唯一
- 从所有新权值中,选择不等于旧权值的最小的,就对应次小生成树
- 具体实现:
- 对于最小生成树,用数组connected[i][j]记录节点i与节点j之间是否连边,用数组maxedge[i][j]记录从i到j的路径上最大的边权重。两个数组随着prim算法的进行而更新。
- 求出最小生成树后,如果两节点i,j间未连边,且从i到j的路径上最大边权重等于从i到j的边权重,则删一边加一边,又是最小生成树,于是不唯一。
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
const int INF = 0x3f3f3f3f;
const int MAXN = 105;
int n, m;
int tot_weight = 0;
bool connected[MAXN][MAXN];
int maxedge[MAXN][MAXN];
bool vis[MAXN];
struct edge {
int to;
int weight;
edge (int _to, int _weight) : to(_to), weight(_weight) {
}
};
struct edge_p : public edge {
int from; /* Special for Second MST */
edge_p (const edge& e, int _pre) : edge(e), from(_pre) {
}
bool operator< (const edge_p& e) const {
return weight > e.weight;
}
};
vector<edge> nxt[MAXN];
void init()
{
tot_weight = 0;
memset(connected, 0, sizeof(connected));
memset(maxedge, 0, sizeof(maxedge));
memset(vis, 0, sizeof(vis));
for (int i = 0; i <= n; ++i)
nxt[i].clear();
}
void prim()
{
priority_queue<edge_p> pq;
/* get ready */
vis[1] = 1;
for (edge e : nxt[1])
pq.push(edge_p(e, 1));
/* do it */
for (int i = 1; i < n; ++i) {
while (vis[pq.top().to])
pq.pop();
edge_p e = pq.top(); pq.pop();
vis[e.to] = 1;
tot_weight += e.weight;
/* Special for Second MST */
connected[e.to][e.from] = connected[e.from][e.to] = 1;
for (int j = 1; j <= n; ++j)
maxedge[e.to][j] = maxedge[j][e.to] = max(e.weight, maxedge[e.from][j]);
for (edge t : nxt[e.to])
if (!vis[t.to])
pq.push(edge_p(t, e.to));
}
}
int main()
{
int T; cin >> T;
while (T--) {
cin >> n >> m;
init();
for (int i = 0; i < m; ++i) {
int u, v, l;
scanf("%d%d%d", &u, &v, &l);
nxt[u].push_back(edge(v, l));
nxt[v].push_back(edge(u, l));
}
prim();
bool isunique = 1;
for (int i = 1; i <= n; ++i) {
for (edge e: nxt[i]) {
if (!connected[i][e.to] && maxedge[i][e.to] == e.weight) {
isunique = 0;
goto END;
}
}
}
END:;
if (isunique)
printf("%d\n", tot_weight);
else
printf("Not Unique!\n");
}
system("pause");
return 0;
}