L2-001 紧急救援(dijkstra算法)
题目:
作为一个城市的应急救援队伍的负责人,你有一张特殊的全国地图。在地图上显示有多个分散的城市和一些连接城市的快速道路。每个城市的救援队数量和每一条连接两个城市的快速道路长度都标在地图上。当其他城市有紧急求助电话给你的时候,你的任务是带领你的救援队尽快赶往事发地,同时,一路上召集尽可能多的救援队。
输入格式:
输入第一行给出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算法:
dijkstra算法是贪心算法在求解路径问题上的应用。
作用:dijkstra算法能够解决边权非负的加权有向图的单起点最短路径问题。也就是说,规定一个起点,就能够得到这个加权有向图中其他点距该起点的最短距离。
数据结构:数组known[ ]用于标记这些点的状态(已知、未知); 数组dis[ ],也就是下表中的dv,表示每个点到起点的距离,附初值时,除了起点自身,其他的点到起点的距离都设为无穷,在实际编程时,可用定义一个很大的数(比如99999999)作为常量为其赋值;数组pre[ ],也就是下表中的pv,表示引起dv变化的最后一个顶点,也就是以这种路径到达这个点经过的前一个点。
算法:以下面这个加权有向图为例,并假设开始结点为v1。初始配置如图9-12所示。每次更新下图的表格,算法都会选择未知的点中dv最小的一个标记为已知,然后去寻找这个点的下几个邻接点,如果该邻接点到这个已知点的距离加上这个已知点的dv小于该邻接点的dv,那么更新dv和pv,这其实就是从这个已知点这里走会更近的意思;如果该邻接点是已知的就跳过(因为每一次都是先将dv最小的点标记为已知,所以该点的dv不会更小)。

过程如图:


下表是每次更新的表格。在下面我直接把书上的讲解搬上来,书是《数据结构与算法分析:C语言描述》。








思路:
了解了dijkstra 以后,再来看这道题,发现题目就是在这个算法的基础上加了一个“救援队”和经过的结点数。那么我们在表格后多加两列就ok了,也就是在程序中加两个数组。最后按顺序输出路径那里使用了递归,具体见代码。
知识点for me:
1、fill()可以按照单元赋值,将一个区间的元素都赋同一个值,它在头文件<algorithm>里面。
它可以赋值任何,比如int数组:fill(arr, arr + n, 要填入的内容); 比如vector:fill(v.begin(), v.end(), 要填入的内容); 比如二维数组fill(f[0], f[0]+N*N, 要填入的内容);
上代码:
第一次写dijkstra,一些数组的命名感觉不是那么合适,将就看吧。
#include <iostream>
#include <algorithm>
using namespace std;
const int inf=;
int v,e,a,b;//点、边、起点、终点
int pv[];//路径中每个点的前一个点 void printPath(int v)//递归输出路线
{
if(v == a) {
printf("%d", v);
return ;
}
printPath(pv[v]);
printf(" %d", v);
}
int main() {
cin>>v>>e>>a>>b;
int help[v];//存储每个村的救援队
int x=;
for(int i=;i<v;i++)
{
cin>>x;
help[i]=x;
}
int f,t,l;
int dis[v][v];//边权
fill(dis[],dis[]+v*v,inf);
for(int i=;i<e;i++)
{
cin>>f>>t>>l;
dis[f][t]=l;
dis[t][f]=l;//注意!!道路是双向的!
}
int known[v]={};//最初所有的点都为未知
int dv[v];
fill(dv,dv+v,inf);//所有点到起点的距离除了起点自身是0,其余都是无穷
dv[a]=; int min;
int minn;
int num[v];//累加的救援队的数量
//num[a]=help[a];
fill(num,num+v,help[a]);
int way[v]={};//从出发点到v结点拥有的最短路径的条数
for(int i=;i<v;i++)//dijkstra
{
min=inf;
minn=-;
//找出未知且dv最小的一个点,将它设为已知
for(int j=;j<v;j++)
{
if(dv[j]<min&&known[j]==){
min=dv[j];
minn=j;
}
}
if(minn==-)//如果剩下未知的点全是dv=inf,break
break;
known[minn]=;
for(int k=;k<v;k++)//找该点邻接的下一个顶点,并求其dv
{
if(dis[minn][k]!=inf&&known[k]==){
if(dis[minn][k]+min<dv[k])
{
dv[k]=dis[minn][k]+min;
pv[k]=minn;
num[k]=num[minn]+help[k];
way[k]=way[minn];
}
else if(dis[minn][k]+min==dv[k]){
way[k]+=way[minn];//无论如何,到达k点的最短路径数量增加:原来的way[k]加上前一个结点的way
if(num[minn]+help[k]>num[k])//比较救援队的数量
{
pv[k]=minn;
num[k]=num[minn]+help[k];
}
}
}
} }
cout<<way[b]<<" "<<num[b]<<endl;
printPath(b);
return ;
}
杀不死我的使我更强大 _(:з」∠)_
L2-001 紧急救援(dijkstra算法)的更多相关文章
- L2-001. 紧急救援 (Dijkstra算法打印路径)
作为一个城市的应急救援队伍的负责人,你有一张特殊的全国地图.在地图上显示有多个分散的城市和一些连接城市的快速道路.每个城市的救援队数量和每一条连接两个城市的快速道路长度都标在地图上.当其他城市有紧急求 ...
- Dijkstra算法C#实现及其布线运用
大家好,我是小鸭酱,博客地址为:http://www.cnblogs.com/xiaoyajiang 以下是空调布线对Dijkstra算法的运用,采用C#实现. 问题:室内机多台,室外机一台.寻找室内 ...
- 单源最短路径算法——Dijkstra算法(迪杰斯特拉算法)
一 综述 Dijkstra算法(迪杰斯特拉算法)主要是用于求解有向图中单源最短路径问题.其本质是基于贪心策略的(具体见下文).其基本原理如下: (1)初始化:集合vertex_set初始为{sourc ...
- 单源最短路——dijkstra算法
Dijkstra算法 1.定义概览 Dijkstra(迪杰斯特拉)算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径.主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止. 问 ...
- Codeforces 843D (Dijkstra算法的优化,动态最短路)
题面 (http://codeforces.com/problemset/problem/843/D) 题目大意: 给定一张带权无向图,有q次操作 操作有两种 1 v 询问1到v的最短路 2 c 将边 ...
- PAT Advanced 1003 Emergency (25) [Dijkstra算法]
题目 As an emergency rescue team leader of a city, you are given a special map of your country. The ma ...
- 求两点之间最短路径-Dijkstra算法
Dijkstra算法 1.定义概览 Dijkstra(迪杰斯特拉)算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径.主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止.D ...
- Dijkstra算法优先队列实现与Bellman_Ford队列实现的理解
/* Dijkstra算法用优先队列来实现,实现了每一条边最多遍历一次. 要知道,我们从队列头部找到的都是到 已经"建好树"的最短距离以及该节点编号, 并由该节点去更新 树根 到其 ...
- 关于dijkstra算法的一点理解
最近在准备ccf,各种补算法,图的算法基本差不多看了一遍.今天看的是Dijkstra算法,这个算法有点难理解,如果不深入想的话想要搞明白还是不容易的.弄了一个晚自习,先看书大致明白了原理,就根据书上的 ...
随机推荐
- webapi datetime类型序列化成json带T且时间不对问题的解决
在global.asax.cs里加入如下代码: protected void Application_Start() { GlobalConfiguration.Configuration.Forma ...
- Regular Expression学习笔记
正则写法 var re = /a/;//简写 /.../里不能为空,因为会误以为是注释: var re = new RegExp('a'); 新建一个RegExp对象:和新建Array对象,Objec ...
- Java Jsp使用
1.Jsp基础 1)Jsp的执行过程 tomcat服务器完成:jsp文件->翻译成java文件->编译成class字节码文件-> 构造类对象-> 调用方法 tomcat的wor ...
- QQ 聊天机器人小薇 2.0.0 发布!
本次发布主要加入了支持讨论组聊天,并增强了稳定性.另外,官方小薇 QQ 机器人已经下线,大家要体验的话请 自建私服~ 简介 XiaoV(小薇)是一个用 Java 写的 QQ 聊天机器人 Web 服务, ...
- sqlite 时间函数及时间处理
SQLite分页显示:Select * From news order by id desc Limit 10 Offset 10这篇文章是根据 SQLite 官方 WIKI 里的内容翻译,如果有什么 ...
- Android SQLite案例
重点掌握execSQL()和rawQuery()方法,rawQuery()方法用于执行select语句. SQLiteOpenHelper,实现了onCreate和onUpgrade方法. 第一次创建 ...
- Python爬虫--- 1.1请求库的安装与使用
来说先说爬虫的原理:爬虫本质上是模拟人浏览信息的过程,只不过他通过计算机来达到快速抓取筛选信息的目的所以我们想要写一个爬虫,最基本的就是要将我们需要抓取信息的网页原原本本的抓取下来.这个时候就要用到请 ...
- qt 样式表基本用法
Qt样式表 QT样式表参考CSS层叠样式表设计,不同之处在于QT样式表应用于Widget世界. 可以使用QApplication::setStyleSheet()函数设置到整个应用程序上,也可以使用Q ...
- php 汉字转拼音函数
function Pinyin($_String, $_Code='UTF8'){ //GBK页面可改为gb2312,其他随意填写为UTF8 $_DataKey = "a|ai|an|ang ...
- 修改virtual box中ubuntu lubuntu 的分辨率
Step1 先用xrandr命令查看能够支持的分辨率 Step2 xrandr --output VGA-1 --size 1280x800 Step3 重启电脑