1.题目
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, C 1 C_1 C1 and C 2 C_2 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 c 1 c_1 c1, c 2 c_2 c2 and L L 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 C 1 C_1 C1 to C 2 C_2 C2.
Output Specification:
For each test case, print in one line two numbers: the number of different shortest paths between C 1 C_1 C1 and C 2 C_2 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.
2.输入输出样例
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
3.题目分析
有N个城市,M条路,每个城市有一定数量的救援队,要求从城市 C 1 C_1 C1 到 C 2 C_2 C2 最短路径有多少条,及最多能有多少救援队。
此题考察的是图算法的最短路径问题,由于结点数量较少(1000以下),因此用邻接矩阵较为合适,除邻接矩阵外还可采用邻接表的方式。对于最短路径问题,本题采用的是Dijkstra算法。
4.具体代码
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxv = 510;
const int INF = 0x3fffffff; //足够大的数
int n, m, st, en; //结点数n,边数m,起始st,终点en
int G[maxv][maxv], weight[maxv]; //邻接矩阵G,点权weight
int w[maxv], num[maxv], d[maxv];//w记录最大点权和,num记录最短路径数,d记录最短路径
bool vis[maxv] = { false }; //vis记录结点是否被访问
void Dijkstra( int s ){
fill( d, d + maxv, INF );
memset( num, 0, sizeof( num ) );
memset( w, 0, sizeof( w ) );
d[s] = 0;
w[s] = weight[s];
num[s] = 1; //以上为初始化
for( int i = 0; i < n; i++ ){
int u = -1, MIN = INF; //u使d[u]最小,MIN存放最小的d[u]
for( int j = 0; j < n; j++ ){ //找到未访问的顶点中d[u]最小的
if( vis[j] == false && d[j] < MIN ){
u = j;
MIN = d[j];
}
}
if ( u == -1 ) break;
vis[u] = true; //标记u为已访问
for( int v = 0; v < n; v++ ){
if( vis[v] == false && G[u][v] != INF ){
//如果v未访问&& u能到达v &&以u为中介点可以使d[v]更优
if( d[u] + G[u][v] < d[v] ){
d[v] = d[u] + G[u][v];
w[v] = w[u] + weight[v];
num[v] = num[u];
}
else if( d[u] + G[u][v] == d[v] ){
//找到一条相同长度的路径
if( w[u] + weight[v] > w[v] ){
w[v] = w[u] + weight[v];
}
num[v] += num[u];
}
}
}
}
}
int main(){
int u, v; //赋值用临时变量
scanf( "%d%d%d%d", &n, &m, &st, &en );
for( int i = 0; i < n; i++ ){
scanf( "%d", &weight[i] ); //读入点权
}
fill( G[0], G[0] + maxv * maxv, 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[en], w[en] );
return 0;
}
5.Dijkstra算法
Dijkstra算法用于解决单源最短路问题,给定图G和起点s,通过算法得到s到达其余各个顶点的最短距离。
Dijkstra算法基本思想是对图G( V, E )设置集合 S 存放已被访问的顶点,之后每次从集合 V-S 中选与起点s的最短距离最小的一个顶点(记为 u ),访问并加入集合 S 。
//G为图,一般设成全局变量;数组d为源点到达各点的最短路径长度,s为起点
Dijkstra( G, d[], s ){
初始化;
for( 循环n次 ){
u = 使d[u]最小的还未被访问的顶点的标号;
记u已被访问;
for( 从u出发能到达的所有顶点v ){
if( v未被访问&&以u为中介点使s到顶点v的最短距离d[v]更优 ){
优化d[v];
}
}
}
}
- 该段来源于《算法笔记》
6.fill函数与memset函数
fill
函数- 在头文件
<algorithm>
中 - 将一个区间的元素都赋予同一个值。
- 在头文件
memset
函数- 在头文件
<cstring>
中 - 按照字节填充同一个字符
- 在头文件
memset
函数要慎用,一般用于填充char
型数组,fill
函数可赋值任何,函数参数:fill(vec.begin(), vec.end(), val);
val为将要替换的值。