1003 紧急事件
作为一个城市的紧急救援队队长,你会得到一张你国家的专业地图。这张地图显示了几个通过道路连接起来的分散的城市。地图上标明了每个城市的救援队伍数量和某两个城市之间每条道路的长度。当其他城市的紧急电话打给你时,你的工作就是带领你的人尽快赶到那里,同时,在路上尽可能多的招集路过城市的救援队伍。
输入规范
每个输入文件包含一个测试用例。对于每个测试用例,第一行包含4个正整数:N表示城市数量(N <= 500)(城市编号从0~N-1),M表示道路数,C1和C2分别表示现在所在城市和需要达到救援的城市。接下来的一行包含N个整数,其中第i个整数表示第i个城市的救援队数量。然后接下来跟随的M行,每一行有三个整数:c1,c2和L,它们分别表示两个城市和两城市之间的道路长度。数据保证至少有一条路径从C1到C2.
输出规范
对于每个测试用例,在一行中打印两个数字:C1到C2之间的不同路径的最短路径长度个数和最短路径长度的时招集的最多救援对数目。一行中的所有数字必须用一个空格隔开,并且在一行的末尾不允许有多余的空格。
输入样例
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
输出样例
2 4
解题思路
dijkstra算法求单源最短路。在求最短路时更新最短路条数和救援队数目。
AC代码
#include <iostream>
#include <cstring>
using namespace std;
const int MAXN = 505;
const int INF = 0x3f;
int value[MAXN]; //value[i]i城市的消防员个数
int g[MAXN][MAXN]; //存储每条边
int dis[MAXN]; //dis[i]表示到i的最短路
bool sign[MAXN]; //标记i是否是最短路
int cnt1[MAXN]; //cnt1[i]表示到i时的最短路个数
int cnt2[MAXN]; //cnt2[i]表示到i时的最短路的最多招集人数(不包含i城市的救援人数)
void dijkstra(int st, int n) { //dijkstra求单源最短路
memset(dis, INF, sizeof(dis));
dis[st] = 0;
cnt1[st] = 1;
for(int i = 0; i < n-1; i++) {
int t = -1;
for(int j = 0; j < n; j++) {
if(!sign[j] && (t == -1 || dis[t] > dis[j])) {
t = j;
}
}
sign[t] = true;
for(int j = 0; j < n; j++) {
if(t != j && dis[j] >= dis[t] + g[t][j]) {
if(dis[j] == dis[t] + g[t][j]) {
cnt1[j] += cnt1[t]; //表示有不同路径,但相同路径长的路径
}else {
cnt1[j] = cnt1[t];
}
cnt2[j] = max(cnt2[j], cnt2[t] + value[t]); //更新最最多招集人数
dis[j] = dis[t] + g[t][j]; //找到一个最短点,更新其他其到起点路径
}
}
}
}
int main() {
memset(g, INF, sizeof(g));
int n, m, c1, c2; //城市数、道路数、出发地、目的地
cin >> n >> m >> c1 >> c2;
for(int i = 0; i < n; i++) {
g[i][i] = 0;
cin >> value[i];
}
for(int i = 0; i < m; i++) {
int a, b, l;
cin >> a >> b >> l;
g[a][b] = l;
g[b][a] = l;
}
dijkstra(c1, n);
//输出最多招集的救援人数时应加上本城市救援人数
cout << cnt1[c2] << ' ' << cnt2[c2]+value[c2] << endl;
return 0;
}