L2-001 紧急救援 (25 分)

L2-001 紧急救援 (25 分)

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

输入格式:

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

 这题是一道典型的迪杰斯特拉的题目,涉及最短路数量、最短路加权、路径打印的迪杰斯特拉的应用。

题目大概就是n个城市,m条路,从s城市到d城市,每一个城市上有不同的加权值,求最短路的数量,并打印加权值最大的那条最短路

#include<stdio.h>
#include<queue>
#include<cstring>
#include<stack>
#define N 510
using namespace std;

int n , m , s , d ;
int city[N][N] ;	//记录图 
int citypower[N] ;	//城市加权值记录 
int dis[N] ;	//记录目前城市所能到城市距离 
int maxx[N] ;	
int pre[N] ;	//路径记录 
int num[N] ;	//道路记录 
int vis[N] ;	//访问记录 
const int inf = 510;	 

void dijkstra()
{
	/*初始化*/
	for(int i=0 ; i < n ; i ++ )
	{
		maxx[i] = 0;
		pre[i]  = -1;
		vis[i] = 0;
	}
	vis[s] = 1;
	pre[s] = -1;
	maxx[s] = citypower[s];
	dis[s] = 0;
	for(int i = 0 ; i < n ; i ++)
	{
		if(i == s) continue;
		dis[i] = city[s][i];
		if(dis[i] != N)//有路径需要更新maxx和pre 
		{
			maxx[i] = citypower[i] + citypower[s];
			pre[i] = s;
		}
	}

	for(int i = 0 ;i < n ; i ++ )
	{
		int min = inf;
		int k;
		for(int j = 0 ; j < n ; j ++ )
		{
			if( !vis[j] && min > dis[j] )
			{
				min = dis[j];
				k = j;
			}
		}
		if( min == inf ) break ;
		vis[k] = 1;
		for(int j = 0 ; j < n ; j ++)
		{
			if(!vis[j])
			{
				if(dis[j] > dis[k] + city[k][j] )
				{
					dis[j] = dis[k] + city[k][j];
					maxx[j] = maxx[k] + citypower[j];
					num[j] = num[k];
					pre[j] = k;
				}
				else if(dis[j] == dis[k] + city[k][j])
				{
					num[j] = num [j] + num[k];
					if(maxx[j]<maxx[k]+citypower[j])
					{
						maxx[j]=maxx[k]+citypower[j];
						pre[j]=k;
					}
				}
			}
		}
	}
}

void printf_path() 
{
/*
路径打印
这里主要用了stack来简化路径打印的过程
实际也可以用递归的方式来完成这个路径的打印 
*/
	stack<int> s;
	for(int i = d; i != -1 ; i = pre[i])
		s.push(i);
	int flag = 0;
	while(!s.empty())
	{
		if(flag)printf(" ");
		else flag = 1;
		printf("%d",s.top());
		s.pop();
	}
	printf("\n");
} 

int main()
{
	while( ~scanf( "%d%d%d%d" , &n , &m , &s , &d) )
	{
		//图初始化 
		for(int i = 0 ; i < n ; i ++)
		{
			for(int j = 0 ; j < n ; j ++)
			city[i][j] = inf;
			city[i][i] = 0;
		}
		for(int i = 0 ; i < n ; i ++)
		{
			scanf( "%d" , &citypower[i] );
			num[i] = 1 ;
		}
		int a , b , v ;
		for(int i = 0 ; i < m ; i ++)
		{
			scanf( "%d%d%d" , &a , &b , &v);
			city[a][b] = city[b][a] = min( city[a][b] , v ) ;
		}
		dijkstra();
		printf("%d %d\n",num[d],maxx[d]);
		printf_path();
	}
	return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值