NOIP专题复习1 图论-最短路
一、知识概述
今天我们要复习的内容是图论中的最短路算法,我们在这里讲3种最短路求法,分别是:floyd,dijkstra,spfa。
那么我们从几道例题来切入今天讲解的算法。
二、典型例题
1、热浪
题目描述
德克萨斯纯朴的民眾们这个夏天正在遭受巨大的热浪!!!他们的德克萨斯长角牛吃起来不错,可是他们并不是很擅长生產富含奶油的乳製品。Farmer John此时以先天下之忧而忧,后天下之乐而乐的精神,身先士卒地承担起向德克萨斯运送大量的营养冰凉的牛奶的重任,以减轻德克萨斯人忍受酷暑的痛苦。
FJ已经研究过可以把牛奶从威斯康星运送到德克萨斯州的路线。这些路线包括起始点和终点先一共经过T (1 <= T <= 2,500)个城镇,方便地标号為1到T。除了起点和终点外地每个城镇由两条双向道路连向至少两个其它地城镇。每条道路有一个通过费用(包括油费,过路费等等)。
给定一个地图,包含C (1 <= C <= 6,200)条直接连接2个城镇的道路。每条道路由道路的起点Rs,终点Re (1 <= Rs <= T; 1 <= Re <= T),和花费(1 <= Ci <= 1,000)组成。求从起始的城镇Ts (1 <= Ts <= T)到终点的城镇Te(1 <= Te <= T)最小的总费用。
输入输出格式
输入格式:
第一行: 4个由空格隔开的整数: T, C, Ts, Te
第2到第C+1行: 第i+1行描述第i条道路。有3个由空格隔开的整数: Rs, Re和Ci
输出格式:
一个单独的整数表示从Ts到Te的最小总费用。数据保证至少存在一条道路。
输入输出样例
输入样例#1:
7 11 5 4
2 4 2
1 4 3
7 2 2
3 4 3
5 7 5
7 3 3
6 1 1
6 3 4
2 4 3
5 6 3
7 2 1
输出样例#1:
7
说明
【样例说明】
5->6->1->4 (3 + 1 + 3)
2、城市路
时间限制: 1 Sec 内存限制: 128 MB
题目描述
罗老师被邀请参加一个舞会,是在城市n,而罗老师当前所处的城市为1,附近还有很多城市2~n-1,有些城市之间没有直接相连的路,有些城市之间有直接相连的路,这些路都是双向的,当然也可能有多条。
现在给出直接相邻城市的路长度,罗老师想知道从城市1到城市n,最短多少距离。
输入
输入n, m,表示n个城市和m条路
接下来m行,每行a b c, 表示城市a与城市b有长度为c的路
输出
输出1到n的最短路
如果1到达不了n,就输出-1
样例输入
5 5
1 2 20
2 3 30
3 4 20
4 5 20
1 5 100
样例输出
90
提示
【数据规模和约定】
1<=n<=2000
1<=m<=10000
0<=c<=10000
三、算法分析
(一)dijkstra算法(对于例题1)
1、算法实现
dijkstra有朴素算法与堆优化的两种。
这个朴素算法非常好写(垃圾的我调了2个小时),我就不多讲了。
我们可以用优先队列来替代堆优化dijkstra,优化扫最小值的过程。
具体实现可以看代码
2、时间复杂度
朴素算法时间复杂度为\(O(N^2)\)
堆优化时间复杂度\(O((n+m)logm)\)
3、代码实现
(1) 朴素算法
//O(n2)的朴素dijkstra
#include<bits/stdc++.h>
using namespace std;
int n,m,tx,ty,dis[5005],a[2505][2505];
bool b[5005];
int main()
{
scanf("%d%d%d%d",&n,&m,&tx,&ty);
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
a[i][j]=100000000;
for (int i=1;i<=m;i++)
{
int x,y,z=0;
scanf("%d%d%d",&x,&y,&z);
a[x][y]=min(a[x][y],z);
a[y][x]=min(a[y][x],z);
}
for (int i=1;i<=n;i++)
{
dis[i]=a[tx][i];
}
dis[tx]=0;
b[tx]=true;
for (int i=1;i<=n-1;i++)
{
int minn=100000000;
int k=0;
for (int j=1;j<=n;j++)
{
if ((!b[j])&&(dis[j]<minn))
{
minn=dis[j];
k=j;
}
}
if (k==0) break;
b[k]=true;
for (int z=1;z<=n;z++)//这里不能再用j,我也不知道为什么。这个地方错了2个小时。。。
{
if(a[z][k]<100000000)
if (dis[k]+a[k][z]<dis[z])
dis[z]=dis[k]+a[k][z];
}
}
printf("%d",dis[ty]);
}
(2)堆优化代码
#include<bits/stdc++.h>
using namespace std;
#define INF 2147483647
int n,m,s,tot;
int Next[500005],head[500005],val[500005],to[500005];
int dis[200005],vis[200005],cnt[200005];
void add(int x,int y,int z)
{
tot++;
to[tot]=y;
val[tot]=z;
Next[tot]=head[x];
head[x]=tot;
}
void dijkstra()
{
priority_queue<pair<int,int> > q;
for (int i=1;i<=n;i++)
dis[i]=INF;
for (int i=1;i<=n;i++)
vis[i]=0;
dis[s]=0;
q.push(make_pair(0,s));
while (q.size())
{
int x=q.top().second; q.pop();
if (vis[x]) continue;
vis[x]=1;
for (int i=head[x];i;i=Next[i])
{
int y=to[i]; int z=val[i];
if (dis[y]>dis[x]+z)
{
dis[y]=dis[x]+z;
q.push(make_pair(-dis[y],y));
}
}
}
}
int main()
{
scanf("%d%d%d",&n,&m,&s);
for (int i=1;i<=m;i++)
{
int x,y,z=0;
scanf("%d%d%d",&x,&y,&z);
add(x,y,z);
}
dijkstra();
for (int i=1;i<=n;i++)
printf("%d ",dis[i]);
return 0;
}
(二)spfa算法(对于例题2)
spfa算法作为重点且最常用。
在稀疏图或有负边权的图上,Dijkstra就失去用武之地了。此时需要使用spfa算法。
1、算法分析
spfa算法与dijkstra算法其实很相像,都需要用到松弛操作。而spfa算法使用一个队列,第一步从源点s开始,把s放进队列。对队列中的每个元素x,广度优先遍历其出边,并针对该元素x的这条出边进行松弛操作。如果松弛可以进行,则把这条出边可达的节点加入队列中。
注意:存在负权环的图中不存在最短路径,SPFA可以用来判断图中是否存在负权环路。
2、时间复杂度
玄学。\(O(kE)\)。对于随机数据来说复杂度较低。
用邻接矩阵存储会导致spfa算法性能大大降低,故需要使用边表(前向星)存图。
3、代码实现
#include<bits/stdc++.h>
using namespace std;
#define INF 2147483647
int n,m,s,tot;
int Next[500005],head[500005],val[500005],to[500005];
//注意,使用next会语法错误,队列要开双倍内存
int dis[50005],vis[50005],cnt[50005];
void add(int x,int y,int z)
{
tot++;
to[tot]=y;
val[tot]=z;
Next[tot]=head[x];
head[x]=tot;
}
bool spfa()
{
queue<int> q;//c++队列的基本操作
for (int i=1;i<=n;i++)
dis[i]=INF;
memset(vis,false,sizeof(vis));
dis[s]=0; vis[s]=true;
q.push(s);//入队列
while (!q.empty())
{
int u=q.front(); q.pop();
vis[u]=false;//队首出队,并且队首可再次访问
for (int i=head[u];i;i=Next[i])
{
int v=to[i];
if (dis[v]>dis[u]+val[i])
{
dis[v]=dis[u]+val[i];
if (!vis[v])
{
q.push(v);
vis[v]=true;
cnt[v]++;
if (cnt[v]>n) return false;
//一个点如果被松弛大于n次,证明不能到达终点。
}
}
}
}
return true;
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=m;i++)
{
int x,y,z=0;
scanf("%d%d%d",&x,&y,&z);
add(x,y,z);
add(y,x,z);
//这里我没有考虑有重边的情况
}
s=1;//为了使大家能更好的灵活应用,所以令起点为1
if (spfa())
{
printf("%d",dis[n]);
} else printf("-1");
}
(三)Floyd
Floyd是一个多元最短路径算法。也就是说,Floyd算法可以求出图中任意两点间的距离。由于Floyd编写较为简单,故不放例题。
以下为floyd的核心代码
for (int k=1;k<=n;k++)
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
if (dis[i][k]+dis[k][j]<dis[i][j])
dis[i][j]=dis[i][k]+dis[k][j];
扩展算法应用(差分约束系统)
算法简介

四、课后作业
1、NOIP2016换教室
2、NOIP2009最优贸易
NOIP专题复习1 图论-最短路的更多相关文章
- NOIP专题复习3 图论-强连通分量
目录 一.知识概述 二.典型例题 1.[HAOI2006]受欢迎的牛 2.校园网络[[USACO]Network of Schools加强版] 三.算法分析 (一)Tarjan算法 (二)解决问题 四 ...
- NOIP专题复习2 图论-生成树
目录 一.知识概述 二.典型例题 1.口袋的天空 三.算法分析 (一)Prim算法 (二)Kruskal 四.算法应用 1.[NOIP2013]货车运输 五.算法拓展 1977: [BeiJing20 ...
- 倍增&矩阵乘法 专题复习
倍增&矩阵乘法 专题复习 PreWords 这两个基础算法我就不多说啦,但是还是要介绍一下" 广义矩阵 "乘法 其实就是把矩阵换成取\(max\),然后都一样... 据神仙 ...
- 状压dp专题复习
状压dp专题复习 (有些题过于水,我直接跳了) 技巧总结 : 1.矩阵状压上一行的选择情况 \(n * 2^n\) D [BZOJ2734][HNOI2012]集合选数 蒻得不行的我觉得这是一道比较难 ...
- NOIp 图论算法专题总结 (1):最短路、最小生成树、最近公共祖先
系列索引: NOIp 图论算法专题总结 (1) NOIp 图论算法专题总结 (2) NOIp 图论算法专题总结 (3) 最短路 Floyd 基本思路:枚举所有点与点的中点,如果从中点走最短,更新两点间 ...
- NOIp知识点复习——最短路计数
$Mingqi\_H$ NOIp 2017考挂了...gg 重新开始好了. 计划明年2月24号前复习完所有的NOIp知识点(毕竟很不熟练啊),之后到七月底前学习完省选的东西(flag?). 从现在开始 ...
- D1图论最短路专题
第一题:poj3660 其实是Floyed算法的拓展:Floyd-Wareshall.初始时,若两头牛关系确定则fij = 1. 对于一头牛若确定的关系=n-1,这说明这头牛的排名是确定的. 通过寻找 ...
- 图论最短路——spfa
今天开始图论的最短路的最后复习,今天自己手打spfa虽然看了一眼书,但是也算是自己打出来的,毕竟很久没打了,而且还是一遍a代码下来15min左右就搞完了,成就感++.所以呢来篇博客记录一下. 香甜的黄 ...
- HDU 5521 [图论][最短路][建图灵感]
/* 思前想后 还是决定坚持写博客吧... 题意: n个点,m个集合.每个集合里边的点是联通的且任意两点之间有一条dis[i]的边(每个集合一个dis[i]) 求同时从第1个点和第n个点出发的两个人相 ...
随机推荐
- 【黑金教程笔记之001】veriloghdl 扫盲文—笔记&勘误
001_veriloghdl 扫盲文—笔记&勘误 2014/10/31 原文作者:akuei2 联系方式:blog.ednchina.con/akuei2 勘误001: Page 3 0.1 ...
- Marching squares 算法 获取轮廓(contour tracing)
https://en.wikipedia.org/wiki/Marching_squares http://blog.csdn.net/coolingcoding/article/details/1 ...
- codeforces 1006 F(折半搜索)
F. Xor-Paths time limit per test 3 seconds memory limit per test 256 megabytes input standard input ...
- BOA服务器搭建步骤
1.下载Boa Webserver的源码 http://www.boa.org/ 2.解压并编译Boa Webserver $ tar xvf boa-0.94.13.tar.gz 由于Boa Web ...
- DB2:在缓冲池 "1" 中当前没有任何页面可用。. SQLCODE=-1218, SQLSTATE=57011, DRIVER=3.61.75
服务器端DB2数据库最近频繁报错: 在缓冲池 , SQLSTATE=, DRIVER= 试验发现简单的查询SQL执行没有问题,复杂的SQL就会报上述错误. 百度发现是因为数据库bufferpool太小 ...
- dalvik.system.VMRuntime 隐藏api的迷惑
[Android UI界面]关于dalvik.system.VMRuntime 的 使用迷惑 我也遇到了相同问题.不知楼主现在解决了没有? 回答1: [Android UI界面]关于dalvik.sy ...
- Java Annontation(注解)详解
java中经常用到注解(Annontation),索性整理了下关于注解的相关知识点: 一.概念 Annontation是Java5开始引入的新特征,类似与.NET 中的attribute.中文名称一般 ...
- 可变类型的安全性——更锋利的C#代码小记(2)
ReadOnlyCollection类型是.NET系统类库提供的一个只读集合类型,它与原来的List<string>不存在任何类型转换关系,因此可以从根本上阻止外部对其的修改操作using ...
- 学JAVA第二十二天,StringBuffer的好处
五一的假期今天就结束了,又要回来上课了. 今天就写一下StringBuffer的好处吧. StringBuffer类的对象能够被多次的修改,并且不产生新的未使用对象. 也就是说,我们平时用String ...
- 锐动SDK针对游戏直播提出的解决方案
方案架构 PC端视频直播与录播功能为游戏厂商宣传,玩家个人秀,大型电竞赛事提供完美的技术解决方案. 直播形式灵活多变不,同音源的选择,画面切换,游戏中嵌入摄像头丰,富解说画面.突出主播个人魅力与粉丝形 ...