Constructing Roads

该问题是一个图论经典题目,要求通过构建最小生成树使得所有村庄连接,已知部分道路。文章介绍了采用Prim算法的解决方案,首先初始化地图和距离,然后通过不断寻找并添加未访问过的节点来构建树,直至所有节点连接。在已有道路基础上,计算最小总长度。
摘要由CSDN通过智能技术生成

题目描述

有N个村庄,从1到N,你应该修建一些道路,这样每两个村庄就可以连接起来。我们说两个村庄A和B相连,当且仅当A和B之间有一条路,或者存在一个村庄C使得A和C之间有一条路,并且C和B相连。我们知道一些村庄之间已经有一些道路了,你的工作是修建一些道路,这样所有的村庄都连接起来,所有道路的长度都是最小的。

输入格式

第一行是整数N (3 <= N <= 100),即村庄数。然后是N行,第i行包含N个整数,第j个数是村庄i和村庄j之间的距离(距离应该是[1,1000]内的整数)。然后输入整数Q (0 <= Q <= N * (N + 1) / 2),然后是Q行,每一行包含两个整数a和b (1 <= a < b <= N),这意味着a村和b村之间的道路已经建成。

输出格式

输出一个整数,该整数是所有要修建的道路的长度,以便所有村庄都连接起来,并且该值是最小的。

Sample Input

3
0 990 692
990 0 179
692 179 0
1
1 2

Sample Output

179

 题目分析

这道题是最小生成树模板题,这里采用prim算法。需要注意的是,题目中已经给出了一些道路的连接,我们在初始化每个点之间的map时,需要将已经连接的道路之间的map设为0。这样就可以直接套用prim模板啦!

Code:

#include<iostream>
#include<cstring>
using namespace std;
#define INF 0x3f3f3f3f
#define maxn 1000
int map[maxn][maxn];
int d[maxn];
int visit[maxn];
int sum;
int minn; int temp;

int n, m; //n个顶点,m条边
int prim()
{
	visit[1] = false; //visit[i]=1表示可以访问该点,visit[i]=0表示不可以访问该点
	d[1] = 0;
	for (int i = 1; i < n; i++) //循环n-1次,找到n-1条边
	{
		minn = INF;
		temp = -1;
		for (int j = 1; j <=n; j++)  //循环n次,找到未加入最小生成树的最小权值的边和点
		{
			if (visit[j] && d[j] < minn)
			{
				minn = d[j];
				temp = j;
			}
		}
		if (temp == -1)
		{
			sum == INF;
			return 0;
		}
		visit[temp] = 0;
		sum += minn;  //更新最小生成树的权值
		for (int k = 1; k <= n; k++)  //更新未加入最小生成树的点和边
		{
			if (visit[k] && d[k] > map[k][temp])
			{
				d[k] = map[k][temp];
			}
		}
	}
	return 0;
}
int main()
{
	cin >> n;
	memset(map, INF, sizeof(map)); //初始化每两点间的权值为无穷
	memset(d, INF, sizeof(d));  //初始化每个点到源点的距离为无穷
	memset(visit, 1, sizeof(visit)); //初始化每个点均可访问
	sum = 0;
	int w;//边(x,y)权值为w
	for (int i = 1; i <= n; i++) //存图 
	{
		for (int j = 1; j <= n; j++)
		{
			cin >> w;
			map[i][j] = w;
		}
	}
	int q; int x, y;
	cin >> q;
	for (int i = 1; i <= q; i++)
	{
		cin >> x >> y;
		map[x][y] = map[y][x] = 0;

	}
	for (int i = 1; i <= n; i++) //初始化每个点到源点的距离(1是源点)
	{
		d[i] = map[i][1];
	}
	prim();
	if (sum == INF)
	{
		cout << "No" << endl;  //该图不连通,不能生成最小生成树
	}
	else
	{
		cout << sum << endl;
	}
	return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值