原题链接:
解题思路:
运用Kruskal最小生成树算法。
- 用Kruskal最小生成树算法对输入数据进行操作;
- 算法输出连通分量只有1个,则存在最小生成树,否则不存在。
- 枚举最小生成树的每一条边,将该边从图中删去,然后对该图进行步骤1。
- 如果得到的最小生成树的总重等于步骤2得到最小生成树的总重,则最小生成树数量加一。
通过画面:
代码:
#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#include <cstdlib>
#include <cassert>
#include <vector>
#include <queue>
#include <algorithm>
#include <set>
using namespace std;
struct edge {
int start, dest, weight, index;
edge(int start = 0, int dest = 0, int weight = 0) : start(start), dest(dest), weight(weight)
{
index = 0;
}
bool operator<(const edge& e2) const
{
if (weight > e2.weight) {
return true;
}
else if (weight == e2.weight && index > e2.index) {
return true;
}
else {
return false;
}
}
};
int kruskal(const vector<vector<edge>>& adjList, bool& flag, int& sumWeight);
bool kruskal(const vector<vector<edge>>& adjList, edge taboo, int min);
int findRoot(vector<int>& setArray, int index);
void unionSet(vector<int>& setArray, int root1, int root2);
int main()
{
int n = 0, m = 0;
assert(scanf("%d %d", &n, &m) == 2);
vector<vector<edge>> adjList(n + 1);
for (int i = 0; i < m; i++) {
edge tmp;
assert(3 == scanf("%d %d %d", &tmp.start, &tmp.dest, &tmp.weight));
tmp.index = i;
adjList[tmp.start].push_back(tmp);
}
bool flag = true;
int sumWeight = 0;
int component = kruskal(adjList, flag, sumWeight);
if (component > 1) {
printf("No MST\n%d\n", component);
}
else {
printf("%d\n", sumWeight);
if (flag) {
puts("Yes");
}
else {
puts("No");
}
}
return 0;
}
int kruskal(const vector<vector<edge>>& adjList, bool& flag, int& sumWeight)
{
vector<int> setArray(adjList.size(), -1);
priority_queue<edge> edgeLeft;
vector<edge> MST;
for (int i = 0; i < (int)adjList.size(); i++) {
for (int j = 0; j < (int)adjList[i].size(); j++) {
edgeLeft.push(adjList[i][j]);
}
}
int cnt = adjList.size() - 2;
while (cnt && !edgeLeft.empty()) {
edge tmp = edgeLeft.top();
edgeLeft.pop();
int root1 = findRoot(setArray, tmp.start);
int root2 = findRoot(setArray, tmp.dest);
if (root1 != root2) {
cnt--;
unionSet(setArray, root1, root2);
sumWeight += tmp.weight;
MST.push_back(tmp);
}
}
for (int i = 0; i < (int)MST.size() && flag; i++) {
flag = kruskal(adjList, MST[i], sumWeight);
}
return cnt + 1;
}
bool kruskal(const vector<vector<edge>>& adjList, edge taboo, int min)
{
vector<int> setArray(adjList.size(), -1);
priority_queue<edge> edgeLeft;
for (int i = 0; i < (int)adjList.size(); i++) {
for (int j = 0; j < (int)adjList[i].size(); j++) {
if (taboo.index != adjList[i][j].index) {
edgeLeft.push(adjList[i][j]);
}
}
}
int cnt = adjList.size() - 2;
int totalWeight = 0;
while (cnt && !edgeLeft.empty()) {
edge tmp = edgeLeft.top();
edgeLeft.pop();
int root1 = findRoot(setArray, tmp.start);
int root2 = findRoot(setArray, tmp.dest);
if (root1 != root2) {
cnt--;
unionSet(setArray, root1, root2);
totalWeight += tmp.weight;
}
}
if (cnt > 0) {
return true;
}
else if (min != totalWeight) {
return true;
}
else {
return false;
}
}
int findRoot(vector<int>& setArray, int index)
{
if (setArray[index] < 0) {
return index;
}
else {
return setArray[index] = findRoot(setArray, setArray[index]);
}
}
void unionSet(vector<int>& setArray, int root1, int root2)
{
if (setArray[root1] < setArray[root2]) {
setArray[root1] += setArray[root2];
setArray[root2] = root1;
}
else {
setArray[root2] += setArray[root1];
setArray[root1] = root2;
}
}