题目描述
作为一个城市的应急救援队伍的负责人,你有一张特殊的全国地图。在地图上显示有多个分散的城市和一些连接城市的快速道路。每个城市的救援队数量和每一条连接两个城市的快速道路长度都标在地图上。当其他城市有紧急求助电话给你的时候,你的任务是带领你的救援队尽快赶往事发地,同时,一路上召集尽可能多的救援队。
输入格式:
输入第一行给出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>
using namespace std;
const int N=510;
int n, m;
int g[N][N];//用邻接矩阵来存储图
int dist[N];//用于存储每个点到起点的最短距离
bool st[N];//用于在更新最短距离时 判断当前的点的最短距离是否确定 是否需要更新
int cnt[N],num[N],people[N],pre[N];
int start;
int ed;
void print(int k)
{
if (k == start)
{
printf("%d", start);
return;
}
print(pre[k]);
printf(" %d", k);
}
void dijkstra()
{
memset(dist,0x3f,sizeof dist);//初始化距离
dist[start]=0;
cnt[start]=1;
num[start]=people[start];
//第一次循环是保证去找每一个点的最短距离
for(int i=0;i<n;i++)
{
int t=-1;// //将t设置为-1 因为Dijkstra算法适用于不存在负权边的图
//该循环是为了找到没有被确定的点当中距离最小的点
for(int j=0;j<n;j++)
{
if(!st[j]&&(t==-1||dist[t]>dist[j])) t=j;// 如果j这个点还没有被用过 或者t没有被尝试过 或者j的距离更近
}
st[t]=true;
//此时的t代表的就是剩余未确定最短路的点中 路径最短的点
for (int j = 0; j < n; j++)
{
//题目要求距离尽可能的短
if (dist[j] > dist[t] + g[t][j])
{
dist[j] = dist[t] + g[t][j];//更新距离
cnt[j] = cnt[t];//更新路径的条数 千万不要写成cnt++
num[j] = num[t] + people[j];//更新救援队的人数
pre[j] = t;
}
else if (dist[j] == dist[t] + g[t][j])//距离相同的情况下 保证救援队尽可能的多
{
cnt[j] += cnt[t];
if (num[j] < num[t] + people[j])
{
num[j] = num[t] + people[j];
pre[j] = t;
}
}
}
}
}
int main()
{
scanf("%d%d%d%d",&n,&m,&start,&ed);
for(int i=0;i<n;i++)
scanf("%d",&people[i]);
memset(g,0x3f,sizeof g);
while(m--)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
g[a][b]=min(g[a][b],c);
g[b][a]=min(g[b][a],c);
}
dijkstra();
printf("%d %d\n", cnt[ed], num[ed]);
print(ed);
return 0;
}
这个把最短路径输出来可太妙了