天梯赛L2-001. 紧急救援(最短路dijkstra)

 

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 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

分析:这题是我dijkstra入门做的第一题,也是我做的第一个L2的题目,对当时的我来说非常难,其实现在想想算一般般吧,不算难,也是要记录一些信息。就是最短路的问题,找一条最短的路径到达救援城市,如果存在多条,则选择能集结消防员最多的一条(经过结点的点信息和最大)。

Ps:不熟悉最短路径算法的(dijkstra)看这里。(有时间补)

#include<stdio.h>
#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
int n,m,s,d,path[500],vertex[500],edge[500][500],vis[500],dis[500],pathnum[500],totval[500],re[500];
/*
vertex记录结点值(救援队数量)
edge记录边值(很大的值表示不可达)
vis记录是否到达过该点
dis记录i点到v0的最短边长
pathnum根据题意记录数量
totval根据题意记录从v0到终点的结点值之和
path根据题意记录i的前驱结点 
*/
void dijkstra(int v0)
{
	//第一次初始下起点信息。 
	vis[v0]=1;//默认第一个起始点访问过
	dis[v0]=0;//默认v0到v0是0
	totval[v0]=vertex[v0];//默认v0到v0的最大结点值和 
	pathnum[v0]=1;//默认v0到v0路数为1	
	//然后初始化所有除起点外的能与起点直达的点的信息。 
	for(int i=0;i<n;i++)
		if(edge[v0][i]!=1e6&&i!=v0){
			path[i]=v0;//第i个结点的前驱结点为v0。
			totval[i]=vertex[v0]+vertex[i];//总共的救援队是起点加该直达点 
			dis[i]=edge[v0][i];//当前最短路径是v0到该点的直达路径值 
			pathnum[i]=1;//数目为1 
		}
	//解题关键 
	for(int i=0;i<n-1;i++){//进行n-1次即可
	    int min=1e6,minval=0,v=v0; /*min v0找到当前未被访问结点的最小当前路径及顶点*/
	    for(int j = 0; j < n; j++)   
                if(vis[j]!=1 && dis[j] < min){//当该点未访问过且当前最短路径小于最小值时更新  
                    min = dis[j];  //找到当前未被访问结点的最小当前路径 
                    v = j; //记录顶点信息。 
                }  
	    vis[v]=1;//找到 
	    for(int j=0;j<n;j++)//对每一个未访问的顶点遍历 
            if(!vis[j])   
            	if(dis[v] + edge[v][j] < dis[j]){//如果当前顶点的最短路小于新找到的点的最短路径加上该点到当前点的路径长则更新  
                    pathnum[j] = pathnum[v];//既然更新,那相应路径数和v点一致  
                    dis[j] = dis[v] + edge[v][j];//当前最短路也要更新  
                    totval[j] = totval[v] + vertex[j];//该点的总结点值和也变了。 
                    path[j] = v;//更新前驱结点。  
                }  
                else if(dis[v] + edge[v][j] == dis[j]){//这题需要注意相等的情况  
                    pathnum[j] += pathnum[v];//原来的路径数加上v点的路径数  
                    if(totval[j] < totval[v] + vertex[j]){//救援队数量较少,即结点和小则要换  
                        totval[j] = totval[v] + vertex[j];  
                        path[j] = v;  
                    }  
                }    
	}	
}
void prt(int x)//一种把路径输出的方式
{
	if(x==s)printf("%d",x);
	else{
		prt(path[x]);
		printf(" %d",x);
	}
}
int main()
{
	//freopen("L2-001. 紧急救援.txt","r",stdin);
    scanf("%d %d %d %d", &n, &m, &s, &d);
    for(int i=0; i<n; i++)  
       scanf("%d",&vertex[i]);
    for(int i=0;i<n;i++){
    	dis[i]=1e6;//把所有顶点距起点的最短路径也置为最大值。 
    	for(int j=0;j<n;j++)
    	    edge[i][j]=1e6;//先把所有顶点置为最大值表示不可达,方便后面选小的。 
    } 	
	for(int i=0;i<m;i++){
		int a,b,c;
		scanf("%d %d %d",&a,&b,&c);
		edge[a][b]=edge[b][a]=c;
	}
	dijkstra(s);
	printf("%d %d\n",pathnum[d],totval[d]);
	prt(d); 
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值