As an emergency rescue team leader of a city, you are given a special map of your country. The map shows several scattered cities connected by some roads. Amount of rescue teams in each city and the length of each road between any pair of cities are marked on the map. When there is an emergency call to you from some other city, your job is to lead your men to the place as quickly as possible, and at the mean time, call up as many hands on the way as possible.
Input Specification:
Each input file contains one test case. For each test case, the first line contains 4 positive integers: N (≤500) - the number of cities (and the cities are numbered from 0 to N−1), M - the number of roads, C1 and C2 - the cities that you are currently in and that you must save, respectively. The next line contains N integers, where the i-th integer is the number of rescue teams in the i-th city. Then M lines follow, each describes a road with three integers c1, c2 and L, which are the pair of cities connected by a road and the length of that road, respectively. It is guaranteed that there exists at least one path from C1 to C2
Output Specification:
For each test case, print in one line two numbers: the number of different shortest paths between C1 and C2, and the maximum amount of rescue teams you can possibly gather. All the numbers in a line must be separated by exactly one space, and there is no extra space allowed at the end of a line.
Sample Input:
5 6 0 2
1 2 1 5 3
0 1 1
0 2 2
0 3 1
1 2 1
2 4 1
3 4 1
结尾无空行
Sample Output:
2 4
这题我第一时间想到的是dp,但是对于单源问题,还是应该使用迪杰斯特拉算法。
1: 找到当前距离已知点集最近的点
2: 将该点加入已知点集,更新其他点集到该点的距离。
迪杰斯特拉算法需要2个数组,记录是否是已知的点,记录未知点到已知点集的最短路径。
需要一个图,此题需要增加两个数组记录第i个点到源点的最短路径数,最大人数。
这个题目的两个问题:
1: 怎么计算人数:人数应该是最短路径上的人数。如果最短路径有多条,那么应该是最大的那条。可以用一个数组记录第i个点到源点的人数。因此,如果更新时发现经过该点更短,那么人数被覆盖。如果发现经过该点和之前距离一样,那么比较人数
2: 怎么计算不同的路径条数:如果i到该点最短路径变短,那么i的条数增加了该点路径数。
总而言之,该法的要点在于,记录其他点到源点的数据,当某个点到达目的点时,算法退出。
#include<iostream>
using namespace std;
int G[501][501];
int Dist[501];
int Known[501] = {0};
int roadsNum2[501] = {0};
int rescueNum2[501] = {0};
int rescuNum[501];
int main(){
int N,M,C1,C2;
cin >> N >> M >> C1 >> C2;
for(int i = 0; i < N; i++){
cin >> rescuNum[i];
}
for(int i = 0; i < N; i++){
for(int j = 0; j < N; j++){
G[i][j] = 0xffffff;
}
G[i][i] = 0;
Dist[i] = 0xffffff;
}
for(int i = 0; i < M; i++){
int c1, c2, L;
cin >> c1 >> c2 >> L;
G[c2][c1] = G[c1][c2] = L;
}
rescueNum2[C1] = rescuNum[C1];
roadsNum2[C1] = 1;
Dist[C1] = 0;
while(1){
int curPos = -1;
int min = 0xffffff;
for(int i = 0; i < N; i++){
if(!Known[i] && Dist[i] < min){
curPos = i;
min = Dist[i];
}
}
if(curPos == C2) break;
Known[curPos] = 1;
for(int i = 0; i < N; i++){
if(Known[i]) continue;
int t = Dist[curPos] + G[curPos][i];//新的长度
int res = rescuNum[i] + rescueNum2[curPos];//新的人数
if(t < Dist[i]){
Dist[i] = t;
rescueNum2[i] = res;
roadsNum2[i] = roadsNum2[curPos];
}
else if(t == Dist[i]){//一定要加else 因为Dist[i]上一步被改掉了
cout<<t<<" "<<Dist[i]<<endl;
rescueNum2[i] = (rescueNum2[i] < res) ? res : rescueNum2[i];
roadsNum2[i] += roadsNum2[curPos];
}
}
}
cout << roadsNum2[C2] << " " << rescueNum2[C2];
}