PTA_21_08_图7 _公路村村通

PTA_21_08_图7 _公路村村通

题目描述

现有村落间道路的统计数据表中,列出了有可能建设成标准公路的若干条道路的成本,求使每个村落都有公路连通所需要的最低成本。

输入格式

输入数据包括城镇数目正整数N(≤1000)和候选道路数目M(≤3N);随后的M行对应M条道路,每行给出3个正整数,分别是该条道路直接连通的两个城镇的编号以及该道路改建的预算成本。为简单起见,城镇从1到N编号。

6 15
1 2 5
1 3 3
1 4 7
1 5 4
1 6 2
2 3 4
2 4 6
2 5 2
2 6 6
3 4 6
3 5 1
3 6 1
4 5 10
4 6 8
5 6 3

输出格式

输出村村通需要的最低成本。如果输入数据不足以保证畅通,则输出−1,表示需要建设更多公路。

12

算法分析

本题采用的是最小生成树的算法,最小生成树主要分为普里姆算法(prim)和克鲁斯卡尔(Kruskal)算法。普里姆算法是以某顶点为起点,逐步找各顶点上最小权值的边来构建最小生成树的。克鲁斯卡尔算法则是直接以边为目标进行构建的。因为权值实在边上,直接找最小权值的边来构建生成树是很自然的思想。

克鲁斯卡尔算法主要针对边来展开,在边数少的时候效率会非常高,所以对稀疏图具有很大的优势

普里姆算法对于稠密图,即边数非常多的情况会好一些。

因此我们将采用普里姆算法来构建最小生成树

利用邻接矩阵来存储各点的信息。

代码实现

#include<stdio.h>
#include<iostream>

using namespace std;
#define MAXSIZE 20
#define INFINITY 65535
bool visited[MAXSIZE];

struct CNode
{
	int numcity;
	int numroad;
	int arc[MAXSIZE][MAXSIZE];//存储连通的权重
	int city[MAXSIZE];
};

typedef struct CNode* Cgraph;

void CreateGraph(Cgraph graph)
{
	int i, j, k;
	int tmp_city, tmp_city2, tmp_weight;
	cin >> graph->numcity >> graph->numroad;

	for (i = 1; i <= graph->numcity; i++)
	{
		for (j = 1; j <=graph->numcity; j++)
		{
			if (i == j)
			{
				graph->arc[i][j] = 0;
			}
			else
			{
				graph->arc[i][j] = INFINITY;
			}
		}
	}

	for (i = 1; i <= graph->numroad; i++)
	{
		cin >> tmp_city >> tmp_city2 >> tmp_weight;
		graph->arc[tmp_city][tmp_city2] = tmp_weight;
		graph->arc[tmp_city2][tmp_city] = tmp_weight;
	}
}

int minispantree_prim(Cgraph graph)
{
	int min, i, j, k;
	int costmoney = 0;
	int value[MAXSIZE];
	int adjvex[MAXSIZE];//保存相关顶点间边的权值点下标
	int lowcost[MAXSIZE];//保存相关顶点间边的权值
	lowcost[0] = 0;//初始化第一个权值为0
	adjvex[0] = 0;//初始化第一个顶点下标为0
	value[0] = 0;//保存到各点的最小权重
	visited[0] = true;//标志是否被访问过
	for (i = 2; i <= graph->numcity; i++)//循环除下标0外的全部顶点
	{
		lowcost[i - 1] = graph->arc[1][i];//v1顶点与指右边的权值存入数组
		adjvex[i-1] = 0;//初始化都为v0的下标
	}
	for (i = 2; i <= graph->numcity; i++)
	{
		min = INFINITY;//初始化最小值权值为无穷,或则可以说是较大的数字
		j = 1;
		k = 0;
		while (j < graph->numcity)
		{
			if (lowcost[j] != 0 && lowcost[j] < min)//如果权值不为0且权值小于min
			{
				min = lowcost[j];//则让当前权值成为最小值
				k = j;//将当前最小值的下标存入k中
			}
			j++;
		}
		value[i-1] = min;
		visited[k] = true;
		lowcost[k] = 0;//将当前顶点的权值设置为0,此顶点完成任务

		for (j = 0; j < graph->numcity; j++)
		{
			if (lowcost[j] != 0 && graph->arc[k + 1][j + 1] < lowcost[j])
			{
				lowcost[j] = graph->arc[k + 1][j + 1];
				adjvex[j] = k;
			}
		}
	}
	for (i = 0; i < graph->numcity; i++)
	{
		costmoney += value[i];
		if (!visited[i])
		{
			cout << "-1";
			return 0;
		}
	}
	cout << costmoney;
	
}


int main()
{
	Cgraph graph;
	graph = (Cgraph)malloc(sizeof(struct CNode));
	CreateGraph(graph);
	minispantree_prim(graph);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值