[PAT-A 1003]Emergency

在这里插入图片描述

考察最短路径 Dijkstra算法

题目大意:给出N个城市,M条无向边,每个城市都有一定的救援小组,所有边的边权(两城市之间的距离),所有城市的点权(每个城市拥有的救援小组的个数)已知,给起点和终点,求起点和终点的最短路径以及最短路径上救援小组的数目之和,如果有多条最短路径,则输出数目之和最大的。

思路:考虑Dijkstra+DFS的方法[算法笔记]最短路径 Dijkstra算法

即第一标尺是求最短路径,第二标尺是求点权之和最大的路径
在第二标尺计算中选择最大的路径。

for (int i = tempPath.size() - 1; i >= 0; i--) {
	int id = tempPath[i];
	tempw += weight[id];
}
if (tempw > maxw) {
	maxw = tempw;
	path = tempPath;
}

AC代码

//1003  Emergency (25 分)
#include<cstdio>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;
const int MAXV = 510;
const int INF = 1000000000;
int n, m, st, ed, G[MAXV][MAXV], weight[MAXV], d[MAXV];
int numPath = 0;//路径条数
int maxw = 0;//最大点权
bool vis[MAXV] = { false };
vector<int>pre[MAXV];
vector<int>tempPath, path;
void Dijkstra(int s) {
	fill(d, d + MAXV, INF);
	d[s] = 0;
	for (int i = 0; i < n; i++) {
		int u = -1, MIN = INF;
		for (int j = 0; j < n; j++) {
			if (vis[j] == false && d[j] < MIN) {
				MIN = d[j];
				u = j;
			}
		}
		if (u == -1)return;
		vis[u] = true;
		for (int v = 0; v < n; v++) {
			if (vis[v] == false && G[u][v] != INF) {
				if (d[v] > G[u][v] + d[u]) {
					d[v] = G[u][v] + d[u];
					pre[v].clear();
					pre[v].push_back(u);
				}
				else if (d[v] == G[u][v] + d[u])pre[v].push_back(u);
			}
		}
	}
}
void DFS(int v) {
	if (v == st) {
		//递归边界
		numPath++;
		int tempw = 0;
		tempPath.push_back(v);
		for (int i = tempPath.size() - 1; i >= 0; i--) {
			int id = tempPath[i];
			tempw += weight[id];
		}
		if (tempw > maxw) {
			maxw = tempw;
			path = tempPath;
		}
		tempPath.pop_back();
		return;
	}
	tempPath.push_back(v);
	for (int i = 0; i < pre[v].size(); i++) {
		DFS(pre[v][i]);
	}
	tempPath.pop_back();
}
int main() {
	(void)scanf("%d %d %d %d", &n, &m, &st, &ed);
	for (int i = 0; i < n; i++) {
		scanf("%d", &weight[i]);
	}
	int u, v;
	fill(G[0], G[0] + MAXV * MAXV, INF);
	for (int i = 0; i < m; i++) {
		scanf("%d %d", &u, &v);
		scanf("%d", &G[u][v]);
		G[v][u] = G[u][v];
	}
	Dijkstra(st);
	DFS(ed);
	printf("%d %d\n", numPath, maxw);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值