作为一个城市的应急救援队伍的负责人,你有一张特殊的全国地图。在地图上显示有多个分散的城市和一些连接城市的快速道路。每个城市的救援队数量和每一条连接两个城市的快速道路长度都标在地图上。当其他城市有紧急求助电话给你的时候,你的任务是带领你的救援队尽快赶往事发地,同时,一路上召集尽可能多的救援队。
输入格式:
输入第一行给出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
结尾无空行
利用Dijkstra最短路径算法
勤写标兵冲冲冲!!!
目录
#include<stdio.h>
typedef struct information{
int visit;//该城市是否被当成最近距离的集合点访问
int min_dist; //该点到目的地最短距离
int num; //在该城市已经集合的救援队数量
int count; //记录到从源点该城市有几条等长的最短路径
int pre; //到该城市的前一个城市序号 ,通过该项遍历
}inf;
inf Visit[521];
int Map[521][521]; //城市地图
int Resuce[521]; //每个城市及救援队人数
void initialize_Visit(int N , int S );//初始化结构数组
void initialize_Map(int N , int M);//初始化地图 (邻接数组)
void Dijkstra_to_find_min_dist(int N ,int S);//使用Dijkstra算法求S->D最短路径
int main(){
int N , M , S , D , i;
int a[521];
int len = 520;
scanf("%d %d %d %d",&N,&M,&S,&D);
int pre = D;
for(i = 0;i < N;i ++){
scanf("%d",&Resuce[i]);
}
initialize_Visit(N , S );//初始化结构数组
initialize_Map(N , M);//初始化地图
Dijkstra_to_find_min_dist(N , S );
printf("%d %d\n",Visit[D].count,Visit[D].num);
while(pre != S){
a[len] = pre;
pre = Visit[pre].pre;
len --;
}
a[len] = S;
for(i = len;i < 521;i ++){
printf("%d",a[i]);
if(i != 520){
printf(" ");
}
}
return 0;
}
void initialize_Visit(int N , int S ){//初始化结构数组
int i;
for(i = 0;i < N;i ++){
Visit[i].visit = 0; //全部未访问
Visit[i].min_dist = 521;//最短路径设为最大值
Visit[i].count = 1;//最短路径数量都为1
Visit[i].num = 0;//救援队数量都为0
}
Visit[S].visit = 1;//设立起始点被访问
}
void initialize_Map(int N ,int M){
int i , j;
for(i = 0;i <= N;i ++){
for(j = 0;j <= N ;j++){
Map[i][j] = 521;//任意两个城市间的距离是521 , 即无穷远;
}
}
int v1 , v2 , dist;
for(i = 0;i < M;i ++){//输入城市地图
scanf("%d %d %d",&v1,&v2,&dist);
Map[v1][v2] = dist;
Map[v2][v1] = dist; //给以邻接矩阵两个通路
}
}
void Dijkstra_to_find_min_dist(int N ,int S){
//根据地图更新Visit
int i , j;
for(i = 0;i <= N;i ++){
Visit[i].min_dist = Map[i][S];
if(Map[i][S] != 521){ // 点i 与 源点有通路
Visit[i].num = Resuce[i] + Resuce[S];//救援队数量更新成i城市与S城市的和
Visit[i].pre = S;//上一个城市是出发地
}
}
for(i = 1;i < N;i ++){ //循环n - 1次 遍历所有剩下的城市,找到最小距离
int minpoint = N;//第N个点已经设置为无穷远
for(j = 0;j < N;j ++){ //找到未访问的最近的城市
if(Visit[j].min_dist < Visit[minpoint].min_dist && Visit[j].visit == 0){
minpoint = j;
}
}
Visit[minpoint].visit = 1;//将找到的最近的城市设为已访问
for(j = 0;j < N;j ++){// 根据找到的最近点更新其他城市的距离
if(Visit[j].visit == 0){
if(Visit[j].min_dist > Visit[minpoint].min_dist + Map[j][minpoint]){//指当j点到目的地的最小距离大于经过点minpoint后再到达目的地的距离
Visit[j].min_dist = Visit[minpoint].min_dist + Map[j][minpoint];//更新j点到目的地的最小距离
Visit[j].num = Visit[minpoint].num + Resuce[j]; //修改救援队的数量 = 上一个城市集合的数量 + 该城市救援队数量
Visit[j].pre = minpoint;//修改上一城市的位置为minpoint
Visit[j].count = Visit[Visit[j].pre].count;//继承从源点到达上一城市路线数量
}else if(Visit[j].min_dist == Visit[minpoint].min_dist + Map[j][minpoint]){//当j点到目的地的最小距离等于经过点minpoint后再到达目的地的距离
Visit[j].count += Visit[minpoint].count;//相等路径的数量 = 原来的数量 + 新路径中到前一个城市的相等路径数量
if(Visit[j].num < Visit[minpoint].num + Resuce[j]){//选择能带领更多救援队的路线
Visit[j].num = Visit[minpoint].num + Resuce[j];
Visit[j].pre = minpoint;//当路径长度相等时 , 取救援队数量最多的城市作为上一个城市的位置
}
}
}
}
}
}