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个点出发的两个人相 ...
随机推荐
- C++实现二叉树(建树,前序,中序,后序)递归和非递归实现
#include<iostream> #include<string.h> #include<stack> using namespace std; typedef ...
- 在 SharePoint 2013 中针对地理位置字段创建地图视图
在 SharePoint 2013 中针对地理位置字段创建地图视图 了解如何通过在 SharePoint 2013 列表中使用地图视图来显示位置信息.您可以通过 SharePoint 用户界面 (UI ...
- 运用NP求解 “跳跃游戏”---计蒜客
计蒜客里面有一道“跳跃游戏的问题” 给定一个非负整数数组,假定你的初始位置为数组第一个下标. 数组中的每个元素代表你在那个位置能够跳跃的最大长度. 你的目标是到达最后一个下标,并且使用最少的跳跃次数. ...
- bzoj3316: JC loves Mkk(单调队列+分数规划)
Description Input 第1行,包含三个整数.n,L,R.第2行n个数,代表a[1..n]. Output 仅1行,表示询问答案.如果答案是整数,就输出整数:否则,输出既约分数“P/Q”来 ...
- (2)css的复合选择器与特性
css的复合选择器与特性 在本篇学习资料中,将深入了解css的相关概念,上一篇介绍的3种基本选择器的基础上,学习3种由基本选择器复合构成的选择器,然后再介绍css的两个重要的特性. 1.复合选择器 复 ...
- ios手机Safari本地服务连不上
问题: 今天在本地起服务准备测下ios手机端页面,结果发现:页面可以打开,但是登录不上. 用alert定位了下,await fn() 报错被try()catch(){}捕获了... 原因: 该机子不支 ...
- DP(两次) UVA 10163 Storage Keepers
题目传送门 /* 题意:(我懒得写,照搬网上的)有n个仓库,m个人看管.一个仓库只能由一个人来看管,一个人可以看管多个仓库. 每个人有一个能力值pi,如果他看管k个仓库,那么所看管的每个仓库的安全值为 ...
- Java中的流(1)流简介
简介 1.在java中stream代表一种数据流(源),java.io的底层数据元.(比作成水管)2.InputStream 比作进水管,水从里面流向你,你要接收,read3.OutputStream ...
- JMeter(十一)内存溢出解决方法
使用jmeter进行压力测试时遇到一段时间后报内存溢出outfmenmory错误,导致jmeter卡死了,先尝试在jmeter.bat中增加了JVM_ARGS="-Xmx2048m -Xms ...
- solr之~模糊查询【转】
solr之~模糊查询 有的时候,我们一开始不可能准确地知道搜索的关键字在 Solr 中查询出的结果是什么,因此,Solr 还提供了几种类型的模糊查询.模糊匹配会在索引中对关键字进行非精确匹配.例如,有 ...