DS村村通工程(Prim算法)

本文解析了如何使用Prim算法解决实际问题,以'村村通'公路工程为例,通过输入顶点数、边及其权重,计算连接所有村落的最低成本,生成最小生成树并输出其总权值及边的信息。

题目描述

"村村通"是国家一个系统工程,其包涵有:公路、电力、生活和饮用水、电话网、有线电视网、互联网等等。

村村通公路工程,是国家为构建和谐社会,支持新农村建设的一项重大举措,是一项民心工程。又称“五年千亿元”工程

该工程是指中国力争在5年时间实现所有村庄通沥青路或水泥路,以打破农村经济发展的交通瓶颈,解决9亿农民的出行难题。

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

要求用Prim算法求解

输入

第1行:顶点数n

第2行:n个顶点编号

第3行:边数m

接着m行:m条边信息,格式为:顶点1 顶点2 权值

最后一行:Prim算法的起点v

输出

第1行:输出最小生成树的权值之和

接着n-1行对应n-1条边信息

按树的生长顺序输出

输入样例1

6
v1 v2 v3 v4 v5 v6 
10
v1 v2 6
v1 v3 1
v1 v4 5
v2 v3 5
v2 v5 3
v3 v4 5
v3 v5 6
v3 v6 4
v4 v6 2
v5 v6 6
v1

输出样例1

15
v1 v3 1
v3 v6 4
v6 v4 2
v3 v2 5
v2 v5 3

NOTICE:

普利姆算法(Prim)主要有以下几点需要注意:(1)所需的变量有visited数组,记录顶点是否加入到U集合中;dis数组,表示从U到V-U中各顶点的最小权值;adj数组,使dis取最小的U中邻接点;mindis,dis中的最小值;minindex,dis中的最小值的下标,weightsum,最小生成树的权值;(2)初始化时将所有的visited初始化为0,所有的dis初始化为MAX,minindex初始化为起点;(3)循环n-1次,每次更新两个任务,更新dis、adj数组和找到新的最小的dis。

#include <iostream>
using namespace std;
#define MAX 66535

struct edge//方便输出而定义的类
{
	string start, end;
	int weight;
};
class Graph
{
private:
	string* data;
	int** Matrix;
	int vertexnum;
	int edgenum;
	string v;//普里姆算法的起点
	int find(string s)//根据顶点信息,返回顶点下标
	{
		for (int i = 0; i < vertexnum; i++)
			if (s == data[i])
				return i;
	}
public:
	Graph()
	{
		cin >> vertexnum;
		data = new string[vertexnum];
		for (int i = 0; i < vertexnum; i++)
			cin >> data[i];
		Matrix = new int* [vertexnum];
		for (int i = 0; i < vertexnum; i++)
			Matrix[i] = new int[vertexnum];
		for (int i = 0; i < vertexnum; i++)
			for (int j = 0; j < vertexnum; j++)
				Matrix[i][j] = MAX;

		cin >> edgenum;
		string s1, s2;
		int w;
		for (int i = 0; i < edgenum; i++)
		{
			cin >> s1 >> s2 >> w;
			Matrix[find(s1)][find(s2)] = w;
			Matrix[find(s2)][find(s1)] = w;
		}

		cin >> v;
	}
	~Graph()
	{
		delete[]data;
		for (int i = 0; i < vertexnum; i++)
			delete[]Matrix[i];
		delete[]Matrix;
	}
	void MinTree_Prim()
	{
		int* visited = new int[vertexnum];
		int* dis = new int[vertexnum];
		int* adj = new int[vertexnum];
		int mindis;
		int min_index;
		int weight_sum = 0;
		
		edge* result = new edge[vertexnum - 1];//根据输出要求,定义一个数组方便输出,元素个数是n-1个(最小生成树)
		int edge_index = 0;

		//初始化
		for (int i = 0; i < vertexnum; i++)
		{
			visited[i] = 0;
			dis[i] = MAX;
		}
		min_index = find(v);
		
		//循环n-1次
		for (int t = 0; t < vertexnum-1; t++)
		{
			visited[min_index] = 1;

			//更新
			for (int i = 0; i < vertexnum; i++)
			{
				if (!visited[i] && Matrix[min_index][i] < dis[i])
				{
					dis[i] = Matrix[min_index][i];
					adj[i] = min_index;
				}
			}

			//找到最小的dis
			mindis = MAX;
			for (int i = 0; i < vertexnum; i++)
				if (!visited[i] && dis[i] < mindis)
				{
					mindis = dis[i];
					min_index = i;
				}

			weight_sum += dis[min_index];
			result[edge_index].start = data[adj[min_index]];
			result[edge_index].end = data[min_index];
			result[edge_index].weight = dis[min_index];
			edge_index++;
		}
		
		//输出
		cout << weight_sum << endl;
		for (int i = 0; i < vertexnum - 1; i++)
		{
			cout << result[i].start << " ";
			cout << result[i].end << " ";
			cout << result[i].weight << endl;
		}
	}
};

int main()
{
	Graph g;
	g.MinTree_Prim();
	return 0;
}

公路村村通问题可以使用Prim算法来解决。Prim算法是一种贪心算法,用于求解加权无向连通图的最小生成树。下面是使用C++实现Prim算法解决公路村村通问题的代码: ```c++ #include <iostream> #include <vector> #include <queue> #include <cstring> using namespace std; const int MAXN = 1005; const int INF = 0x3f3f3f3f; int n, m; int cost[MAXN][MAXN]; int lowcost[MAXN]; bool vis[MAXN]; void prim(int start) { memset(lowcost, INF, sizeof(lowcost)); memset(vis, false, sizeof(vis)); lowcost[start] = 0; priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq; pq.push(make_pair(0, start)); while (!pq.empty()) { int u = pq.top().second; pq.pop(); if (vis[u]) continue; vis[u] = true; for (int v = 1; v <= n; v++) { if (!vis[v] && cost[u][v] < lowcost[v]) { lowcost[v] = cost[u][v]; pq.push(make_pair(lowcost[v], v)); } } } } int main() { cin >> n >> m; memset(cost, INF, sizeof(cost)); for (int i = 1; i <= m; i++) { int u, v, w; cin >> u >> v >> w; cost[u][v] = cost[v][u] = w; } prim(1); int ans = 0; for (int i = 1; i <= n; i++) { if (lowcost[i] == INF) { cout << "No solution" << endl; return 0; } ans += lowcost[i]; } cout << ans << endl; return 0; } ``` 其中,cost数组表示每条边的权值,lowcost数组表示当前生成树到每个点的最小边权值,vis数组表示当前点是否已经加入生成树。在prim函数中,首先将起点的lowcost设为0,然后将起点加入优先队列中。每次从队列中取出lowcost最小的点u,将其加入生成树中,并更新与u相邻的点的lowcost值。最后遍历所有点,如果有点的lowcost值为INF,则说明该点无法到达,输出"No solution",否则输出所有lowcost值的和即为最小成本。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值