进阶实验6-3.6 最小生成树的唯一性 (35 分)
给定一个带权无向图,如果是连通图,则至少存在一棵最小生成树,有时最小生成树并不唯一。本题就要求你计算最小生成树的总权重,并且判断其是否唯一。
输入格式:
首先第一行给出两个整数:无向图中顶点数 N(≤500)和边数 M。随后 M 行,每行给出一条边的两个端点和权重,格式为“顶点1 顶点2 权重”,其中顶点从 1 到N 编号,权重为正整数。题目保证最小生成树的总权重不会超过 230。
输出格式:
如果存在最小生成树,首先在第一行输出其总权重,第二行输出“Yes”,如果此树唯一,否则输出“No”。如果树不存在,则首先在第一行输出“No MST”,第二行输出图的连通集个数。
输入样例 1:
5 7
1 2 6
5 1 1
2 3 4
3 4 3
4 1 7
2 4 2
4 5 5
输出样例 1:
11
Yes
输入样例 2:
4 5
1 2 1
2 3 1
3 4 2
4 1 2
3 1 3
输出样例 2:
4
No
输入样例 3:
5 5
1 2 1
2 3 1
3 4 2
4 1 2
3 1 3
输出样例 3:
No MST
2
#include<stdio.h>
#include<stdlib.h>
struct Edge {
int Vertex1;
int Vertex2;
int Weight;
int Flag;
};
int* InitializeUnion(int N);
void Combine(int* a, int Root1, int Root2);
int FindRoot(int* a, int Item);
int Kruskal(int N, int M);
#include<algorithm>
using namespace std;
struct EdgeRule {
bool operator()(const struct Edge& E1, const struct Edge& E2) {
return E1.Weight < E2.Weight;
}
};
int Work(int N, struct Edge* EdgeSet, int* Union, int th, int M);
int main()
{
int N, M;
scanf("%d %d", &N, &M);
Kruskal(N, M);
}
int* InitializeUnion(int N)
{
int* a = (int*)malloc(sizeof(int) * (N+1));
for (int i = 1; i <= N; i++)
{
a[i] = -1;
}
return a;
}
int FindRoot(int* a, int Item)
{
int Root = Item;
while (a[Root] > 0)
{
Root = a[Root];
}
return Root;
}
void Combine(int* a, int Root1, int Root2)
{
if (a[Root1] < a[Root2])
{
a[Root1] += a[Root2];
a[Root2] = Root1;
}
else
{
a[Root2] += a[Root1];
a[Root1] = Root2;
}
}
struct Edge* InitializeEdge(int M)
{
struct Edge* EdgeSet = (struct Edge*)malloc(sizeof(struct Edge) * M);
for (int i = 0; i < M; i++)
{
scanf("%d %d %d", &EdgeSet[i].Vertex1, &EdgeSet[i].Vertex2, &EdgeSet[i].Weight);
EdgeSet[i].Flag = 0;
}
sort(EdgeSet, EdgeSet + M, EdgeRule());
return EdgeSet;
}
int Kruskal(int N,int M)
{
int* Union = InitializeUnion(N);
struct Edge* EdgeSet = InitializeEdge(M);
int EdgeNum = 0;
int WeightSum = 0;
int Root1, Root2;
int SubSet=0;
for (int i = 0; i < M; i++)
{
Root1 = FindRoot(Union, EdgeSet[i].Vertex1);
Root2 = FindRoot(Union, EdgeSet[i].Vertex2);
if (Root1 != Root2)
{
WeightSum += EdgeSet[i].Weight;
Combine(Union, Root1, Root2);
EdgeNum++;
}
}
for (int i = 1; i <= N; i++)
{
if (Union[i] < 0)
{
SubSet++;
}
}
if(SubSet>1)
printf("%s\n%d","No MST",SubSet);
else {
int* Union2 = InitializeUnion(N);
int Back = Work(N - 1, EdgeSet, Union2, 0, M);
if (Back == 1)
{
printf("%d\n%s", WeightSum, "Yes");
}
else
{
printf("%d\n%s", WeightSum, "No");
}
}
return EdgeNum;
}
int Work(int N, struct Edge* EdgeSet, int* Union, int th,int M)
{
if (N == 0)
return 1;
else
{
int Root1, Root2,i,Root1Num,Root2Num,Root1C,Root2C,Root1A,Root2A;
for (i = th; i < M; i++)
{
Root1 = FindRoot(Union, EdgeSet[i].Vertex1);
Root2 = FindRoot(Union, EdgeSet[i].Vertex2);
if (Root1 != Root2)
{
Root1Num = Union[Root1];
Root2Num = Union[Root2];
Combine(Union, Root1, Root2);
Root1A = Union[Root1];
Root2A = Union[Root2];
EdgeSet[i].Flag = 1;
int Back = Work(N - 1, EdgeSet, Union, i + 1, M);
if (Back == -1)
return -1;
else {
Union[Root1] = Root1Num;
Union[Root2] = Root2Num;
for (int j = i + 1; j < M; j++)
{
if (EdgeSet[j].Weight == EdgeSet[i].Weight && EdgeSet[j].Flag == 0)
{
Root1C = FindRoot(Union, EdgeSet[j].Vertex1);
Root2C = FindRoot(Union, EdgeSet[j].Vertex2);
if (Root1C != Root2C)
{
return -1;
}
}
else if (EdgeSet[j].Weight > EdgeSet[i].Weight)
{
return 1;
}
}
return 1;
}
}
}
}
}