L2-001 紧急救援 (25 分)(Dijkstra,找路径,详解)

138 篇文章 1 订阅
88 篇文章 5 订阅

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

输入第一行给出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

迪杰斯特拉算法!!
求起点到终点的最短路径和最长救援队,和这个题非常像这个题,也是迪杰斯特拉的算法
但是有一部分我还没弄懂,就是找最短路径的操作:

现在弄懂了,这里的意思是,每当更新路径时,都在pre位置存储上一个点的编号,然后根据递归调用,输出从起点到终点,比如路线是0 1 3,那么就在pre存储的是 -1,0,1,这样在递归时,就能还原出路径了

void getpath(int d){
	if(d!=-1){
		getpath(pre[d]);
		if(flag==0){
			cout<<d;
			flag=1;
		}
		else cout<<" "<<d;
	}
}

上面的代码需要我再理解理解,先把博客写上。详解明天写!
复盘成功,学无止境,迪杰斯特拉求路径我是第一次明白方法,还有很多不会的,加油!

#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<set>
#include<stack>
#include<string>
#include<queue>
#include<vector>
#include<cctype>
#include<map>
using namespace std;
const int maxn = 501;
const int inf = 1e9;
int dis[maxn];//到起点的最短路径
int num[maxn];//每个城市救援队的数目
int maxnum[maxn];//最大救援队数目
int coun[maxn];//最短的路径条数
int a[maxn][maxn];//每个城市间的距离
int vis[maxn]={0};//判断是否被标记
int pre[maxn];//求找路径,但是我还不会!呜呜
int flag=0;//输出格式
int n,m,s,d;
void Dijkstra(int s){
	fill(dis,dis+maxn,inf);
	memset(maxnum,0,sizeof(maxnum));
	memset(coun,0,sizeof(coun));
	dis[s]=0;
	maxnum[s] = num[s];
	coun[s]=1;
	for(int i=0;i<n;i++){
		int u=-1,minn=inf;
		for(int j=0;j<n;j++){
			if(!vis[j]&&minn>dis[j]){
				minn=dis[j];
				u=j;
			}
		}
		if(u==-1) return ;
		vis[u]=1;
		for(int v=0;v<n;v++){
			if(!vis[v]&&a[u][v]!=inf){
				if(dis[v]>dis[u]+a[u][v]){//更新最短路径
					dis[v]=dis[u]+a[u][v];
					maxnum[v]=maxnum[u]+num[v];
					coun[v]=coun[u];
					pre[v]=u;//存储此位置的上一个位置
				}
				else if(dis[v]==dis[u]+a[u][v]){
					if(maxnum[v]<maxnum[u]+num[v]){//更新最大救援数目
						maxnum[v]=maxnum[u]+num[v];
						pre[v]=u;//存储此位置的上一个位置
					}
					coun[v]+=coun[u];
				}
				
			}
		}
	}
	
}

void getpath(int d){
	if(d!=-1){
		getpath(pre[d]);
		if(flag==0){
			cout<<d;
			flag=1;
		}
		else cout<<" "<<d;
	}
}
int main(){
	memset(pre,-1,sizeof(pre));//这里不知道为啥要都先置-1
	cin>>n>>m>>s>>d;
	fill(a[0],a[0]+maxn*maxn,inf);
	for(int i=0;i<n;i++){
		cin>>num[i];
	}
	for(int i=0;i<m;i++){
		int x,y,di;
		cin>>x>>y>>di;
		a[x][y]=a[y][x]=di;
	}
	vv.push_back(s);
	Dijkstra(s);
	cout<<coun[d]<<" "<<maxnum[d];
	cout<<endl;
	getpath(d);
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_努力努力再努力_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值