# 算法设计第二次上机作业-The Unique MST
题目描述
判断一个图的MST树是否唯一
输入
第一行是输入的测试样例的个数
后面的每一个样例的第一行都给出两个数n和m,给出了总节点数和边数。
之后的m行给出每条边的两个节点和权重。
输出
如果MST唯一,则输出权重
若不唯一,则输出"Not Unique!"
思路:
查找MST树用Krustal算法,将所有的边进行排序,每次都选择权重最小的边,判断这条边和已经在mst_edges中的边是否连通,若不连通则加入到集合中。
判断连通则是用并查集,并查集可以看这篇博客并查集详解
AC的代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring>
#define Max 10005
using namespace std;
struct edge {
int to;
int from;
int weight;
};
int p[Max]; //记录每个节点的上级节点(不是祖先)
edge edges[Max];
vector<int> mst_edges;
int cmp(edge edge1, edge edge2) {
return edge1.weight < edge2.weight;
}
int find_root(int x) { //并查集找到每一个节点的祖先节点
if(p[x]!=-1) {
return find_root(p[x]);
}
else {
return x;
}
}
void Krustal(int n, int m) {
int num = 0, weight = 0;
memset(p, -1, sizeof(p));
mst_edges.clear();
for(int i=0; i<m; i++) {
if(num == n-1) break;
int px = find_root(edges[i].from);
int py = find_root(edges[i].to);
if(px != py) { //这条边和其他的边不连通
p[px] = py;
num++;
weight += edges[i].weight;
mst_edges.push_back(i);
}
}
bool flag = true;
int size = mst_edges.size();
for(int i=0; i<size; i++) { //去掉mst_edges中的每一条边,看剩下的边能否构成一棵MST树
int ans = 0;
num = 0;
memset(p, -1, sizeof(p));
for(int j=0; j<m; j++) {
if(mst_edges[i] == j) continue;
int px = find_root(edges[j].from);
int py = find_root(edges[j].to);
if(px != py) {
p[px] = py;
ans += edges[j].weight;
num++;
}
}
if(num == n-1 && ans == weight) { //如果剩下的边能够构成一棵树并且权重和之前的相同,说明不唯一
flag = false;
break;
}
}
if(flag == true) cout<<weight<<endl;
else cout<<"Not Unique!"<<endl;
}
int main(int argc, const char * argv[]) {
// insert code here...
int num, n, m;
scanf("%d",&num);
for(int i=0; i<num; i++) {
scanf("%d%d", &n, &m);
for(int j=0; j<m; j++) {
scanf("%d%d%d", &edges[j].from, &edges[j].to, &edges[j].weight);
}
sort(edges, edges+m, cmp);
Krustal(n, m);
}
return 0;
}
出现的bug有:
- 中间出现过TEL,因为Max值设小了,所以如果值设小了不一定会出现Time Error
- 判断是否是树的时候一开始写成了边数-1,应该是节点数-1