进阶实验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
最小生成树问题。
如果图的连通集个数>1,则最小生成树不存在;图的连通集个数==1,则最小生成树存在。
在收录最小dist值至最小生成树中时,如果最小dist值有多个时,则最小生成树不唯一。例如样例2,收录完顶点1、2、3后,收录顶点4时,1和4之间边的权重等于2,3和4之间边的权重也等于2,这两种途径都可以把4收录进最小生成树内,因此最小生成树不唯一。
C语言实现:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define Infinity 10000
struct graph
{
int Ne;
int Nv;
int * * M;
};
typedef struct graph * Graph;
Graph CreateGraph(int N);
void DFS(Graph G, int v);//深度优先搜索
int * Visited;
int flag = 0;//标记最小生成树是否唯一,若唯一flag=0;若不唯一flag=1
int main()
{
int i;
int N, M;
scanf("%d %d", &N, &M);
Graph G;
G = CreateGraph(N);
G->Ne = M;
Visited = (int *)malloc(N * sizeof(int));
for (i = 0; i < N; i++)
{
Visited[i] = 0;
}
int v1, v2, w;
for (i = 0; i < M; i++)//无向图
{
scanf("%d %d %d", &v1, &v2, &w);
G->M[v1 - 1][v2 - 1] = w;
G->M[v2 - 1][v1 - 1] = w;
}
int cnt = 0;//cnt记录连通集的个数
for (i = 0; i < N; i++)
{
if (Visited[i] == 0)
{
DFS(G, i);
cnt++;
}
}
if (cnt > 1)//连通集超过1个,则最小生成树不存在
{
printf("No MST\n");
printf("%d", cnt);
}
else//1个连通集,最小生成树存在
{
int * dist;//dist记录顶点到最小生成树的最短距离
dist = (int *)malloc(N * sizeof(int));
for (i = 0; i < N; i++)//初始化
{
Visited[i] = 0;
dist[i] = Infinity;
}
int weight = 0;//总权重
dist[0] = 0;//从顶点0开始考虑
Visited[0] = 1;
for (i = 0; i < N; i++)//顶点0的邻接点dist值
{
if (G->M[0][i] != -1)
{
dist[i] = G->M[0][i];
}
}
int min, index;
int f = 0;
while (1)
{
f = 0;
min = Infinity;
for (i = 0; i < N; i++)//寻找未访问顶点中dist值最小的顶点index
{
if (min > dist[i] && Visited[i] == 0)
{
f = 1;
min = dist[i];
index = i;
}
}
if (f == 0) { break; }
weight = weight + dist[index];//总权重增加
dist[index] = 0;//收录顶点index
Visited[index] = 1;
for (i = 0; i < N; i++)
{
if (G->M[index][i] != -1 && Visited[i] == 0)
{
if (dist[i] > G->M[i][index])//收录顶点index后dist[i]值可更小,则更新dist[i]
{
dist[i] = G->M[i][index];
}
else if (dist[i] == G->M[i][index] && Visited[i] == 0)//有多个dist[i]等于min,生成树不唯一
{
flag = 1;
}
}
}
}
printf("%d\n", weight);
if (flag == 1) { printf("No"); }
else { printf("Yes"); }
}
return 0;
}
Graph CreateGraph(int N)
{
int i, j;
Graph G;
G = (Graph)malloc(sizeof(struct graph));
G->Ne = 0;
G->Nv = N;
G->M = (int * *)malloc(N * sizeof(int *));
for (i = 0; i < N; i++)
{
G->M[i] = (int *)malloc(N * sizeof(int));
}
for (i = 0; i < N; i++)
{
for (j = 0; j < N; j++)
{
G->M[i][j] = -1;
}
}
return G;
}
void DFS(Graph G, int v)//深度优先搜索遍历树
{
int i;
int N = G->Nv;
Visited[v] = 1;
for (i = 0; i < N; i++)
{
if (G->M[v][i] != -1 && Visited[i] == 0)
{
DFS(G, i);
}
}
}