PTA-图-最短路径-城市间紧急救援

题目要求

作为一个城市的应急救援队伍的负责人,你有一张特殊的全国地图。在地图上显示有多个分散的城市和一些连接城市的快速道路。每个城市的救援队数量和每一条连接两个城市的快速道路长度都标在地图上。
当其他城市有紧急求助电话给你的时候,你的任务是带领你的救援队尽快赶往事发地,同时,一路上召集尽可能多的救援队。

输入格式:

输入第一行给出4个正整数N、M、S、D,其中N(2≤N≤500)是城市的个数,顺便假设城市的编号为0 ~ (N−1);M是快速道路的条数;S是出发地的城市编号;D是目的地的城市编号。
第二行给出N个正整数,其中第i个数是第i个城市的救援队的数目,数字间以空格分隔。随后的M行中,每行给出一条快速道路的信息,分别是:城市1、城市2、快速道路的长度,中间用空格分开,数字均为整数且不超过500。输入保证救援可行且最优解唯一。

输出格式:

第一行输出最短路径的条数和能够召集的最多的救援队数量。第二行输出从S到D的路径中经过的城市编号。数字间以空格分隔,输出结尾不能有多余空格。

输入样例:

4 5 0 3
20 30 40 10
0 1 1
1 3 2
0 3 3
0 2 2
2 3 2

输出样例:

2 60
0 1 3

解题思路

利用Dijsktra算法进行变式,因为题目要求的权值有两种,且长度优先级大于救援人数,因此自定义一个类/结构体来表示dist[],并按照需求重载操作符。

class node
{
public:
	int dis;
	int manNum;
	node(int a = INF, int b = 0):dis(a),manNum(b){}
	bool operator < (const node & a) {
		if (dis == a.dis)
			return manNum > a.manNum;
		else
			return dis < a.dis;
	}
	bool operator > (const node& a) {
		return !(*this < a);
	}
	node operator + (const node& a) {
		return node{ dis + a.dis, manNum + a.manNum };
	}
};

本题重点是最短路径条数,要想到如 a->b->c , a->c的条数等于a->b的条数加上b->c的条数这个递推思想,具体实现方法就是数组再每次遍历邻接点的时候进行判断。

//entry 入口
//pathchoice entry->每个点的最短路径条数
pathchoice[entry] = 1;
//访问v的每一个邻接点w
for (int w = 0; w < n; w++) {
	if (!visted[w] && mg[v][w] != INF) {
		node temp = node{ mg[v][w],rescue[w] };				
		if (dist[w].dis == temp.dis + dist[v].dis)            //1.如果entry->w的最短距离和entry->v->w的距离相等,则entry->w的条数就要进行递推
			pathchoice[w] += pathchoice[v];
		if (dist[w] > dist[v] + temp) {
			dist[w] = dist[v] + temp;
			path[w] = v;
			pathchoice[w] = max(pathchoice[w],pathchoice[v]);      //2.真正要保留的是最短路径的条数
		}				
	}
}

这里要解释一下为什么1,2两点是分开且顺序不能颠倒。因为最短路径条数不同于最优路径,最短路径不需要考虑救援人数,如果颠倒了顺序就可能会导致最短路径条数因为最优路径的关系先一步发生变化。
然后2的地方用了一个max(),是因为即使满足1也有可能进入这个if(详见claass node中重载的运算符), 本来pathchoice[w] = pathchoice[v] 应该是第一次遍历到做的赋值,但是可能在前几次遍历中已经经过了1
所以应该保留最大的哪个数才是最短路径的条数。

AC代码参考: github

猜你喜欢

转载自www.cnblogs.com/sjh001/p/12911854.html