L2-001 紧急救援 (25 分)
作为一个城市的应急救援队伍的负责人,你有一张特殊的全国地图。在地图上显示有多个分散的城市和一些连接城市的快速道路。每个城市的救援队数量和每一条连接两个城市的快速道路长度都标在地图上。当其他城市有紧急求助电话给你的时候,你的任务是带领你的救援队尽快赶往事发地,同时,一路上召集尽可能多的救援队。
输入格式:
输入第一行给出4个正整数N、M、S、D,其中N(2≤N≤500)是城市的个数,顺便假设城市的编号为0 ~ (N−1);M是快速道路的条数;S是出发地的城市编号;D是目的地的城市编号。
第二行给出N个正整数,其中第i个数是第i个城市的救援队的数目,数字间以空格分隔。随后的M行中,每行给出一条快速道路的信息,分别是:城市1、城市2、快速道路的长度,中间用空格分开,数字均为整数且不超过500。输入保证救援可行且最优解唯一。
输出格式:
第一行输出最短路径的条数和能够召集的最多的救援队数量。第二行输出从S到D的路径中经过的城市编号。数字间以空格分隔,输出结尾不能有多余空格。
输入样例:
4 5 0 3
20 30 40 10
0 1 1
1 3 2
0 3 3
0 2 2
2 3 2
输出样例:
2 60
0 1 3
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
int City[505]; // 救援队数
int Path[505][505]; // 路径
int Dis[505]; // 起点到各个点的距离
int Pre[505]; // 标记每个点的前一个点
int Count[505]; // 每个点的最短路径条数
bool Visited[505]; // 标记点
void Dijkstra(int S, int D, int N);
int Find(int pos); // 这个函数可能有点麻烦,暂时想不到什么更好的方法
int main()
{
int N, M, S, D;
scanf("%d%d%d%d", &N, &M, &S, &D);
for (int i = 0; i < N; ++i)
{
for (int j = 0; j < N; ++j)
{
if (i == j)
Path[i][j] = 0;
else
Path[i][j] = INF;
}
Visited[i] = false;
}
for (int i = 0; i < N; ++i)
scanf("%d", &City[i]);
int x, y, len;
for (int i = 0; i < M; ++i)
{
scanf("%d%d%d", &x, &y, &len);
Path[x][y] = Path[y][x] = len;
}
Dijkstra(S, D, N);
return 0;
}
void Dijkstra(int S, int D, int N)
{
Visited[S] = true;
Pre[S] = S;
Count[S] = 0;
for (int i = 0; i < N; ++i)
{
Dis[i] = Path[S][i];
if (Dis[i] != INF)
Pre[i] = S, Count[i] = 1;
}
for (int i = 1; i < N; ++i)
{
int min_dis = INF, mark;
for (int j = 0; j < N; ++j)
{
if (!Visited[j] && Dis[j] < min_dis)
{
min_dis = Dis[j];
mark = j;
}
}
Visited[mark] = true;
for (int j = 0; j < N; ++j)
{
if (j != mark && Dis[j] > Dis[mark] + Path[mark][j])
{
Dis[j] = Dis[mark] + Path[mark][j];
Pre[j] = mark;
Count[j] = Count[mark];
}
else if (j != mark && Dis[j] == Dis[mark] + Path[mark][j])
{
int f1 = Find(mark);
int f2 = Find(Pre[j]);
if (f1 > f2)
{
Dis[j] = Dis[mark] + Path[mark][j];
Pre[j] = mark;
}
Count[j] += Count[mark];
}
}
}
printf("%d %d\n", Count[D], Find(D));
int pos = D, temp[505], index = 0;
while (Pre[pos] != pos)
{
temp[index++] = pos;
pos = Pre[pos];
}
printf("%d", S);
for (int i = index - 1; i >= 0; --i)
printf(" %d", temp[i]);
}
int Find(int pos)
{
int sum(0);
while (Pre[pos] != pos)
{
sum += City[pos];
pos = Pre[pos];
}
return sum + City[pos];
}