A 1003 Emergency
Problem Description
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
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
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个点(编号为0到n-1),若干条边,每条边和每个点都有权值。求某个起点到某个终点的最短路数量,和所有最短路方案里,一条路线上所有点的权值和最大是多少。
解题思路:
经典Dijsktra算法 + roads数组(存储最短路数量)+teams数组(存储最短路线上点的权值和最大值)。难点在于teams数组和roads数组的更新方式和判断条件。详情看代码和注释理解。
AC代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define max(a, b) ((a) > (b) ? (a) : (b))
const int maxn = 504;
int graph[maxn][maxn]; //存图
int sos[maxn]; //每个城市等待救援的队伍数量
int vis[maxn]; //标记是否访问过
int d[maxn]; //起点到每个点的最短距离
int roads[maxn]; //起点到每个点的最短路数量
int teams[maxn]; //起点到每个点在距离最短的情况下最多救援几支队伍
int main(int argc, char **argv){
int n,m,u,v,w,start,destination;
scanf("%d%d%d%d",&n,&m,&start,&destination);
for(int i=0;i<maxn;i++){
for(int j=0;j<maxn;j++){
graph[i][j]=INF; //初始化,所有点都没有边相连
}
}
fill(vis, vis+maxn, 0); //初始化所有点都未访问
fill(d, d+maxn, INF); //初始化,起点到每一个点距离都为无穷大
fill(roads, roads+maxn, 0); //初始化,起点到每一个点的路线数都为0
fill(teams, teams+maxn, 0); //初始化,起点到每一个点能救援的队伍数量为0
for(int i=0; i<n; i++){
scanf("%d",&sos[i]);
}
for(int i=0; i<m; i++){
scanf("%d%d%d",&u,&v,&w);
graph[u][v]=w;
graph[v][u]=w;
}
teams[start]=sos[start]; //起点的待救队伍是一定能救的
roads[start]=1; //起点到起点有且只有一条路
d[start]=0; //起点到起点的距离为0
for(int i=0; i<n; i++){
int p=-1; int minE = INF; //p用于记录,未访问的点集中到起点距离最短的点
for(int j=0; j<n; j++){
if(!vis[j] && d[j]<minE){
p=j;
minE=d[j];
}
}
if(p==-1){break;} //如果p是-1说明所有点都遍历完了,退出
vis[p]=true;
for(int j=0; j<n; j++){
if(!vis[j] && graph[p][j]!=INF){
if(d[j]>graph[p][j]+d[p]){
d[j]=graph[p][j]+d[p];
teams[j] = teams[p]+sos[j]; //更新最短路,可救援队伍数量为中转站p队伍数量与终点j队伍数量之和
roads[j] = roads[p]; //最短路径数就是起点到中转站p的最短路径数
}else if(d[j] == graph[p][j]+d[p]){
teams[j] = max(teams[p]+sos[j],teams[j]); //比较筛选出能救出队伍数的最大数量
roads[j] += roads[p]; //更新最短路数量
}
}
}
}
printf("%d %d",roads[destination],teams[destination]);
return 0;
}