L2-001. 紧急救援(dijkstra+dfs)

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

输入格式:

输入第一行给出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
测试点结果用时(ms)内存(kB)得分/满分
0答案正确235212/12
1答案正确23527/7
2答案正确24802/2
3答案正确3915044/4

题意目标:求最短路径条数和最大救援数量及其经过的城市编号

思路:通过dijkstra求得最短路,并在这个过程中,不断修改队伍数量和最短路径条数。再通过dfs遍历求得路径,要点是抓住:当前最优点路径长度=上个点最优点路径长度+两点间长度&&当前最优点路径救援队伍数量=上个点最优点路径救援队伍数量+当前节点救援队伍数量。即可解答!

思路转载自:http://www.bubuko.com/infodetail-2385127.html

        但这个博主并没有AC,原因在于数据初始化方面的问题。


代码如下:

#include<cstdio>
#define Max 505
int n,m,s,d;
int dis[Max][Max],peo[Max];

int dmin[Max],sum[Max],way[Max];

//dmin[i]为s->i的最短距离,way[i]为s->i的最短路径数量,sum[i]为s->所有路径中队伍数量的最大值

bool move[Max];//标记是否访问过
void dijkstra(){
	int i,j;
	for(i=0;i<n;i++){//初始化信息
		dmin[i]=dis[s][i];
		move[i]=false;
		sum[i]=peo[i];
		way[i]=1;
		if(dmin[i]<Max){
			sum[i]+=peo[s];
		}
	}
	dmin[s]=0;
	move[s]=true;
	for(i=1;i<=n-1;i++){
		int minw=Max;
		int k;
		for(j=0;j<n;j++){//找出当前距离s最近的点

			if(!move[j]){
				if(minw>dmin[j]){
					minw=dmin[j];
					k=j;
				}
			}
		}
		move[k]=true;
		
		for(j=0;j<n;j++){//修改在当前情况下,其他点能否通过k达到更优的状态。
			//printf("%d  %d %d %d %d %d\n",k,j,dmin[j],sum[j],way[j],move[j]);
			if(!move[j]){
				if(dmin[j]==dmin[k]+dis[k][j]){
					way[j]+=way[k];
					if(sum[j]<sum[k]+peo[j])
						sum[j]=sum[k]+peo[j];
				}
				if(dmin[j]>dmin[k]+dis[k][j]){
					dmin[j]=dmin[k]+dis[k][j];
					sum[j]=sum[k]+peo[j];
					way[j]=way[k];
				}
			}
			//printf("%d  %d %d %d %d %d\n",k,j,dmin[j],sum[j],way[j],move[j]);	
		}
	}
}


void dfs(int end,int num){
	if(end==s)
		return;
	for(int i=0;i<n;i++){
		if(num-peo[end]==sum[i]&&dmin[end]-dis[end][i]==dmin[i]){
			dfs(i,sum[i]);
			printf("%d ",i);
		}
	}
}

int main(){
	scanf("%d%d%d%d",&n,&m,&s,&d);
	for(int i=0;i<n;i++)
		for(int j=0;j<n;j++)
			dis[i][j]=Max;
	for(int i=0;i<n;i++)
		scanf("%d",&peo[i]);
	for(int i=0;i<m;i++){
		int x,y,z;
		scanf("%d%d%d",&x,&y,&z);
		dis[x][y]=dis[y][x]=z;
	}
	dijkstra();
	printf("%d %d\n",way[d],sum[d]);
	dfs(d,sum[d]);
	printf("%d\n",d);
	return 0;
} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值