7-35 城市间紧急救援 (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
该题的做法同之前做过的一道PTA甲级题目1003 Emergency (25 分)
不同的是需要添加一个path[]数组用于保存第i结点为终点的最短路时i结点前一个结点编号。最后再利用一个栈将路径输出。
#include<iostream>
#include<stack>
using namespace std;
#define INF 0xffffff
int n,m,c1,c2;
int edge[510][510]; //存储各城市之间的联通关系
int weight[510]; //存储各城市的救援队数目
int dist[510]; //存储出发点到点i的最短路径的路径长度
int num[510]; //表示从出发点到i结点最短路径的条数
int w[510]; //表示从出发点到i点的救援队的数目和
int s[510]; //存储已访问的点集
int path[510];
void Dijkstra(int v)
{
fill(dist, dist + 510, INF);
dist[v]=0;
//s[v]=1;
w[v]=weight[v];
num[v]=1;
path[v]=-1;
for(int i = 0;i<n;i++)
{
int u = -1,minx = INF;
for(int j = 0;j<n;j++)
{
if(minx>dist[j]&&s[j]==0) //在没加入到s集合中的点中寻找dist最小的点
{
u = j;
minx = dist[j];
}
}
if(u ==-1) break; //不连通终止
s[u] = 1; //将点u加入s集合
for(int j = 0;j<n;j++)
{
if(s[j]==0&&edge[u][j]!=INF)
{
if(dist[u]+edge[u][j]<dist[j])
{
dist[j] = dist[u]+edge[u][j];
num[j] = num[u];
w[j] = w[u]+weight[j];
path[j]=u;
}
else if(dist[u]+edge[u][j]==dist[j])
{
num[j] = num[j]+num[u];
if(w[u]+weight[j]>w[j]){
w[j] = w[u]+weight[j];
path[j]=u;
}
}
}
}
}
}
int main()
{
cin>>n>>m>>c1>>c2;
for(int i = 0;i<n;i++)
cin>>weight[i];
//edge初始化
for(int i = 0;i<n;i++)
for(int j = 0;j<n;j++)
edge[i][j] = INF;
for(int i = 0;i<m;i++)
{
int a,b,l;
cin>>a>>b>>l;
edge[a][b] = edge[b][a] = l;
}
Dijkstra(c1);
cout<<num[c2]<<" "<<w[c2]<<endl;
//利用栈输出路径
stack<int>ss;
ss.push(c2);
while(path[c2]!=0)
{
ss.push(path[c2]);
c2=path[c2];
}
cout<<c1;
while(!ss.empty())
{
cout<<" "<<ss.top();
ss.pop();
}
return 0;
}