数据结构PTA习题:进阶实验6-3.6 最小生成树的唯一性 (35分)——最小生成树

进阶实验6-3.6 最小生成树的唯一性 (35分)

给定一个带权无向图,如果是连通图,则至少存在一棵最小生成树,有时最小生成树并不唯一。本题就要求你计算最小生成树的总权重,并且判断其是否唯一。

输入格式:
首先第一行给出两个整数:无向图中顶点数 N(≤500)和边数 M。随后 M 行,每行给出一条边的两个端点和权重,格式为“顶点1 顶点2 权重”,其中顶点从 1 到N 编号,权重为正整数。题目保证最小生成树的总权重不会超过 2​30​​。

输出格式:
如果存在最小生成树,首先在第一行输出其总权重,第二行输出“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);
		}
	}
}

### 关于最小生成树普里姆算法的PTA题目解析 #### 一、题目描述 假设在一个无向图中有多个城市,每两个相邻的城市之间有一条道路连接,并且道路上有修建成本。现在要在这几个城市间建立通信网络,使得任意两座城市都能通过这些道路互相到达,同时使总建设费用最低。 #### 二、解决方案——普里姆算法实现 对于上述问题可以采用普里姆算法来求解最小生成树,从而得到最优方案。该方法的核心是从任选的一个起点出发,逐步加入最近邻接节点直到覆盖所有顶点为止[^1]。 ```python import heapq def prim_algorithm(graph, start_vertex): mst = [] total_weight = 0 visited = set([start_vertex]) edges = [(weight, start_vertex, to) for to, weight in graph[start_vertex].items()] heapq.heapify(edges) while edges: (weight, from_vertex, to_vertex) = heapq.heappop(edges) if to_vertex not in visited: visited.add(to_vertex) mst.append((from_vertex, to_vertex, weight)) total_weight += weight for next_to, next_weight in graph[to_vertex].items(): if next_to not in visited: heapq.heappush(edges, (next_weight ,to_vertex, next_to)) return mst, total_weight ``` 此段代码实现了基于优先队列优化版本的普里姆算法,在处理稀疏图时效率更高。给定一个表示各城市间路径及其重关系的数据结构`graph`以及起始位置`start_vertex`作为输入参数,函数返回构建完成后的最小生成树边列表和总的值之和[^2]。 #### 三、具体实例析 考虑如下简单案例: | 城市 | A | B | C | |------|-------|--------|---------| | **A**| - | 7 | 5 | | **B**| 7 | - | 8 | | **C**| 5 | 8 | - | 从表格可以看出这是一个完全图,其中包含了三个城市的相互距离信息。应用上面提到的方法计算得出的结果应当是选择AC这条最短路加上AB构成整个系统的最小花费路线。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值