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
题意:
给出N个城市,M条无向边,每个城市中都有一定数目的救援小组,所有边的边权已知。先给出起点和终点,求从起点到终点的最短路径条数以及最短路径上救援小组数目之和。如果最后有多条最短路径,输出数目之和最大值
输入:第一行:N(0~N-1) M 起点 终点
第二行:依次给出每个节点的点权值
接下来M行:第三行:0到1 之间的长度为1
思路:
Dijkstra算法解决最短路径问题
本题难点在于:不仅要求得最短路径,同时需要最短路径条数和最短路径上的最大点权之和
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 510;
const int INF = 100000000;
int n, m, st, ed;
int G[maxn][maxn]; //邻接矩阵存储
int weight[maxn]; //存储点权
//分别记录最短距离,最大点权之和,最短路径条数
int d[maxn], w[maxn], num[maxn];
bool vis[maxn] = {false};
void Dijkstra(int s){ //s为起点
fill(d, d + maxn, INF); //将最短距离均初始化为最大值
memset(num, 0, sizeof(num));
memset(w, 0, sizeof(w));
d[s] = 0; //起点到自己的最短距离为0
w[s] = weight[s]; //s到自己的最大点权即为自身的点权
num[s] = 1;
for(int i = 0; i < n; i++){
int u = -1, MIN = INF;
for(int j = 0; j < n; j++){
//找到未访问的顶点中d[]最小的
if(vis[j] == false && d[j] < MIN){
u = j;
MIN = d[j];
}
}
//找不到小于INF的d[u], 说明剩下的顶点和起点s不连通
if(u == -1)
return;
vis[u] = true;
for(int v = 0; v < n; v++){
//如果v未访问 && u能到达 v
if(vis[v] == false && G[u][v] != INF){
// 以u 为中介点可以使d[v]变小
if(d[u] + G[u][v] < d[v]){
d[v] = d[u] + G[u][v]; //更新
w[v] = w[u] + weight[v]; //有了更小的d[],覆盖之前的点权
num[v] = num[u]; //此时v最短路径条数即为到u的最短路径条数
}
//找到一条相同长度的路径
else if(d[u] + G[u][v] == d[v]){
if(w[u] + weight[v] > w[v]){ //如果以u为中介时点权值更大
w[v] = w[u] + weight[v]; //更新最大点权值
}
//注意最短路径条数与点权无关,加上u的最短路径条数即可
num[v] += num[u];
}
}
}
}
}
int main(){
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] + maxn * maxn, 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);
printf("%d %d\n", num[ed], w[ed]);
return 0;
}
Dijsktra算法模板:
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxv = 1000;
const int INF = 1000000000;
int n, m, s, G[maxv][maxv];
int d[maxv];
bool vis[maxv] = {false};
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){
u = j;
MIN = d[j];
}
}
if(u == -1)
return;
vis[u] = true;
for(int v = 0; v < n; v++){
if(vis[v] == false && G[u][v] != INF && d[u] + G[u][v] < d[v]){
d[v] = d[u] + G[u][v];
}
}
}
}
int main(){
int u, v, w;
scanf("%d%d%d", &n, &v, &s);
fill(G[0], G[0] + maxv * maxv, INF);
for(int i = 0; i < m; i++){
scanf("%d%d%d", &u, &v, &w);
G[u][v] = w;
}
Dijkstra(s);
for(int i = 0; i < n; i++){
printf("%d ", d[i]);
}
return 0;
}