PAT L2-001 紧急救援 dijikstra 最短路

L2-001. 紧急救援

时间限制
200 ms
内存限制
65536 kB
代码长度限制
8000 B
判题程序
Standard
作者
陈越

作为一个城市的应急救援队伍的负责人,你有一张特殊的全国地图。在地图上显示有多个分散的城市和一些连接城市的快速道路。每个城市的救援队数量和每一条连接两个城市的快速道路长度都标在地图上。当其他城市有紧急求助电话给你的时候,你的任务是带领你的救援队尽快赶往事发地,同时,一路上召集尽可能多的救援队。

输入格式:

输入第一行给出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 320 30 40 100 1 11 3 20 3 30 2 22 3 2

输出样例:

 
 

2 600 1 3



C4的练习题,感觉L1挺水的就从L2开始做了。第一题就卡了……赶紧学习了最短路的dijkstra算法。
这题基本上就是在模板上稍加修改就可以做了。注意更新时候的细节,我一开始因为考虑不周,反复修改了好多次,具体细节都写在注释里了。

#include <iostream>
#include<cstring>
#include<cstdio>
#define inf 1000000
using namespace std;
int map[501][501],pathnum[501],pathcity[501],vis[501],dis[505],car[505],carnum[505],path[505];
//map记录道路,pathnum记录到这一点的路径数,pathcity记录到该点的上一个点,vis记录是不是被计算过,dis当前到起始点的最短距离,car表示人数,carnum不是路径到这里总人数。
void kij(int n,int v0){
	int i,j,minn,mark;
	vis[v0]=1;
	dis[v0]=0;
	pathnum[v0]=1;
	pathcity[v0]=v0;
	carnum[v0]=car[v0];//定义起点
	for(i=0;i<n;i++){
		dis[i]=map[i][v0];
		if(dis[i]!=inf&&!vis[i]){
			pathnum[i]=1;
			pathcity[i]=v0;
			carnum[i]=carnum[v0]+car[i];
		}//更新与起点相连的
	}
	for(i=0;i<n;i++){
		minn=inf;
		mark=v0;
		for(j=0;j<n;j++){
			if(!vis[j]&&dis[j]<minn){
				minn=dis[j];
				mark=j;
			}
		}//寻找当前最短点,
		vis[mark]=1;//标记
		for(j=0;j<n;j++){//由最短点延伸,更新距离
			if(!vis[j]){
				if(dis[mark]+map[mark][j]<dis[j]){//从最短点mark过比当前最短还短
					pathnum[j]=pathnum[mark];//路径数和到mark的路径数相同
					pathcity[j]=mark;//前一个点为mark
					dis[j]=minn+map[mark][j];//更新距离
					carnum[j]=carnum[mark]+car[j];//更新人数
				}
				else if(minn+map[mark][j]==dis[j]){//如果两条路一样短,则开始增加路径数
					pathnum[j]+=pathnum[mark];//增加
					if(carnum[mark]+car[j]>carnum[j]){//比较谁拉的人多
						pathcity[j]=mark;
						carnum[j]=car[j]+carnum[mark];//更新
					}
				}
			}
		}
	}
}
int main()
{
	int n,m,s,d,i,j;
	int a,b,c;
	scanf("%d%d%d%d",&n,&m,&s,&d);
	for(i=0;i<n;i++){
		for(j=0;j<n;j++)map[i][j]=inf;//先都设为inf
	}
	for(i=0;i<n;i++)scanf("%d",&car[i]);
	for(i=0;i<m;i++){
		scanf("%d%d%d",&a,&b,&c);
		map[a][b]=c;
		map[b][a]=c;//注意道路是双向的
	}
	kij(n,s);
	int temp=d;
	int tot=0;
	while(temp!=s){
		path[tot++]=temp;
		temp=pathcity[temp];
	}//读取路径
	printf("%d %d\n",pathnum[d],carnum[d]);
	//printf("%d\n",tot);
	for(i=tot;i>=0;i--){
		printf("%d",path[i]);
		if(i>0)printf(" ");
		else printf("\n");//别忘了格式
	}

    return 0;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值