天梯赛 L2-001 紧急救援 (迪杰斯特拉算法实现)

题目链接
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

题目可用迪杰斯特拉算法实现,刚开始,题目中说的是“第一行输出最短路径的条数和能够召集的最多的救援队数量。”我误解了,误以为是求得的路径有几段路线,这导致只过了两个测试点,应该是求出最短路径的条数,也就是相等的最短路线条数。还有,本题是无向图,不可按有向图来做。
代码如下:

#include<bits/stdc++.h>
#define MaxInt 3657
#define MvNum 500
using namespace std;
typedef struct
{
	int vnum;//顶点个数 
	int anum;//边个数 
	int arc[500][500];//矩阵 
}Graph;
void ShortestPath_DIJ(Graph G,int v0,int Path[MvNum],int a[500],int num[500])//迪杰斯特拉算法 
{
	int n,v,i,w,min,j;
	vector<pair<int,int> > D(MvNum);
	bool S[MvNum];
	n=G.vnum;
	memset(num,0,sizeof(num));
	num[v0]=1;
	for(v=0;v<n;v++)
	{
		S[v]=false;
		D[v].first=G.arc[v0][v];
		D[v].second=a[v];
		if(D[v].first<MaxInt) 
		{
			Path[v]=v0;
			D[v].second+=D[v0].second;
			num[v]=num[v0];
		}
		else Path[v]=-1;
	}
	S[v0]=true;
	D[v0].first=0;
	for(i=1;i<n;i++)
	{
		min=MaxInt;
		for(w=0;w<n;w++)
		{
			if(!S[w])
			{
				if(D[w].first<min)
				{
					v=w;
					min=D[w].first;
				}
			}		
		}
		S[v]=true;
		for(w=0;w<n;w++)
			{
				if(D[v].first+G.arc[v][w]<D[w].first) 
				{				
					D[w].first=D[v].first+G.arc[v][w];
					D[w].second=D[v].second+a[w];	
					Path[w]=v;
					num[w]=num[v];					
				}
				else if(D[v].first+G.arc[v][w]==D[w].first)//路径长度相等时比较救援队数量 
				{	
					if(D[w].second<D[v].second+a[w])			
					{						
						D[w].second=D[v].second+a[w];					
						Path[w]=v;
					}
					num[w]+=num[v];	
				}
			}
	}					
}
int main()
{
	Graph G;
	int n,m,s,d,i,t,a[500],st,en,Path[500],path[100],sum=0,j,num[500];//a[500]代表城市救援队数量 
	// freopen("data.txt","r",stdin);//Path[]代表DIJ求出的路径 ,path[]代表s->d的最短路径正常序列 
	cin>>n>>m>>s>>d;//num[]代表最短路径相同的路径条数 
	G.vnum=n;
	G.anum=m; 
	for(i=0;i<n;i++)
	{
		cin>>a[i];//城市救援队 
	}
	for(i=0;i<n;i++)
	{
		for(j=0;j<n;j++)
		G.arc[i][j]=MaxInt;//初始化图 
	}	
	for(i=0;i<m;i++)
	{
		cin>>st>>en>>t;
		G.arc[en][st]=G.arc[st][en]=t;//创建图 
	}
	ShortestPath_DIJ(G,s,Path,a,num);
	i=d;t=1;path[0]=d;
	while(i!=s)
	{
		path[t++]=Path[i];//得到最短路径正常顺序path[] 
		i=Path[i];
	}
	for(i=0;i<t;i++)
		sum+=a[path[i]];//最短路径长度	
	cout<<num[d]<<" "<<sum<<endl;	
	for(i=t-1;i>=0;i--)
	{
		cout<<path[i];
		if(i!=0)
		cout<<" ";
	}
	
	
 } 
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值