# PAT甲级-1003 Emergency (25)（25 分）-图之最短路径

#### 1003 Emergency (25)（25 分）

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

//c++代码
#include<cstdio>
#include<algorithm>
using namespace std;

/*题目所需所有常量与变量：n=点数，maxn=点的编号范围，e=边数,s=起点,d=终点*/
const int INF = 1000000000;
const int maxn = 510;
int n, e, s, d;

/*关于边的变量：el（edge_length缩写）存储边权(本例为城市之间的距离)*/
int el[maxn][maxn];

/*关于点的变量：v存储点是否被访问过，noh(node_hands缩写)存储点权(本例为每个城市的人手)*/
int v[maxn];
int noh[maxn];

/*关于路径的变量：pathl(path_length缩写)存储从起点到所有点的最短路径的边权(本例为起点城市到所有城市的最短路径的距离)，
pathc(path_count缩写)存储从起点到其他点的最短路径的数目；maxh(max_hands缩写)存储从起点到其他点的全部最短路径中的点权最大值(本例为起点城市到其他城市的所有最短路径中，人手最多的那条路径的人手数)*/
int pathl[maxn];
int pathc[maxn];
int maxh[maxn];

/*用dijkstra求出起点到所有点的最短路径，并记录最短路径中点权的最大值*/
void dijkstra() {

/*初始化所有属性：起点到自身的最短路径距离path[s]为0，其最短路径数目pathc[s]只有一条；

fill(pathl, pathl + maxn, INF);
pathl[s] = 0;
pathc[s] = 1;
maxh[s] = noh[s];

/*不断更新起点到其他点的最短路径，并更新最短路径中的点权*/
while (1) {

/*找出本轮尚未确定最短路径的城市中，起点到剩余城市中，距离最小minl的那个城市mini。

*/
int minl = INF, mini = -1;
for (int i = 0; i < n; i++) {
if (v[i] == 1)continue;
if (pathl[i] < minl) {
minl = pathl[i];
mini = i;
}
}
if (minl == INF || mini == d)break;
v[mini] = 1;

/*尝试从起点城市-城市mini-其他城市i，如果路径更短，则更新;*/
for (int i = 0; i < n; i++) {
if (v[i] == 1 || el[mini][i] == 0)continue;
/*如果城市i已经处理好，或者城市mini到不了城市i，则跳过；*/
int templ = pathl[mini] + el[mini][i];
int temph = maxh[mini] + noh[i];
if (templ < pathl[i]) {
pathl[i] = templ;
maxh[i] = temph;
pathc[i] = pathc[mini];
}
/*如果从城市mini过去城市i的路径更短，则更新所有属性*/
else if (templ == pathl[i]) {
pathc[i] += pathc[mini];
if (temph > maxh[i]) {
maxh[i] = temph;
}
/*如果从城市mini到城市i的路径跟之前的路径距离相同，则更新最短路径数。但人手更多,即点权更大，则更新最多人手数*/
}
}
}
}

int main() {
/*接收所有数据*/
scanf("%d %d %d %d", &n, &e, &s, &d);
for (int i = 0; i < n; i++) {
scanf("%d", &noh[i]);
}
for (int i = 0; i < e; i++) {
int in1, in2, in3;
scanf("%d %d %d", &in1, &in2, &in3);
el[in1][in2] = el[in2][in1] = in3;
}

/*用dijkstra求出起点到所有点的最短路径*/
dijkstra();

/*输出起点到目标的最短路径的数目，以及所有最短路径中，最大的人手数*/
printf("%d %d\n", pathc[d], maxh[d]);

return 0;
}