最短路问题

解决最短路问题有以下算法:Dijkstra算法,Bellman-Ford算法,Floyd算法,和SPFA算法和启发式搜索算法A*;

每个算法都有它的特点可以解决某些特定的问题,例如:Floyd算法可以求解任意两点之间的最短路径长度,SPFA可以判定是否存在负环问题

一. Dijkstra 算法:

  解决的问题:<非负权图单源最短路>1.从某一点出发到所有点的最短路径,就是最后更新的dis数组2.从某一个点到出发到具体某一点的最短路,只要第一次吧这个点加入最短路就可以终止程序了。3.注意Dijkstar 算法不能处理负权边

  思想:贪心

  做法: 每次将未加入最短路径的点种找距离出发点最近的点加入,然后用这个点更新所有没有加入的点到起始点的最小距离,每次加入一个点更新一次,直到所有的点都加入数组后结束,就可以统计出这个点到所有点的最短路径了

  算法复杂度:斐波那契堆的复杂度O(E+VlgV)

  核心代码:

 void dijk(int s , int n)
{
int i , j , k ;
for( i = ; i <= n ;i++)
{
p[i] = false;
dist[i] = mp[s][i];
}
p[s] = true;
dist[s] = ;
for(i = ; i < n ; i++)
{
int Min = INF;
int k = ;
for( j = ; j <= n ;j++)
{
if(!p[j]&&dist[j]<Min)
{
Min = dist[j];
k = j;
}
}
if(Min==INF) return ;
p[k] = true;
for(j = ; j <= n ;j++)
{
if(!p[j]&&mp[k][j]!=INF&&dist[j]>dist[k]+mp[k][j])
dist[j] = dist[k]+mp[k][j];
}
}
}

二.BellmanFord 算法和SPFA 算法(Shortest Path Faster Algorithm)

  解决的问题:1.权值有负值得图的单源最短路,并且可以检测到负环,注意,由于B_F算法的复杂度过高而且都可以用SPFA解决,所以我们只学习SPFA算法(一个特例:bellman可以检测并输出负环,单SPFA不能输出负环)2.最长路

  思想:松弛操作

  做法:设置一个队列,开始将初始点加入这个队列中,如果队列不空的话,取出队列顶端的元素i,用队列顶端的元素对所有的点j进行松弛操作  if(mp[i][j]!=INF&&dis[j]>dis[i]+mp[i][j]) dis[j] = dis[i]+mp[i][j];  如果j点没有在队列中,说明它还有更新其他点的潜力,所以将被更新的j点也加入到队列中去,设置一个计数器,设总点数为n,如果一个点进队的次数大于n则说明存在负环。

  算法复杂度:O(kE) k是每个节点进队的次数,一般来说k<=2;但是这里的复杂度证明是有问题的,所以SPFA的最坏的情况应该是O(VE)

  核心代码:

、初始化所有点,每一个点保存一个值,表示从源点到达这个点的距离,将源点的值设为0,其他点的值设为无穷大(表示不可达)
、进行循环,循环n-1次。在循环内部,遍历所有的边,进行松弛计算
、遍历图中所有的边,判断是否存在这样情况d[v]>d[u]+w(u,v);
,则表示图中存在从源点可达的负权回路

Bellman-Ford 算法思路

 int SPFA()
{
memset(inq,,sizeof(inq));
for(int i = ;i <= n ;i++)
dis[i] = INF;
top = ;
dis[] = ;
que[top++] = ;
inq[]=true;
for(int i = ;i != top ;i = i+%N)//队列不为空,注意i和top不是同时循环到下一次的
{
int u = que[i];
inq[u]=false;
for(int j = head[u] ; j!=- ;j = edge[j].next)
{
Edge e = edge[j];
if(dis[e.to]>dis[u]+e.w)
{
dis[e.to] = dis[u]+e.w;
if(inq[e.to]==false)
{
que[top++] = e.to;
top %= N;//循环队列
inq[e.to] = true;
}
}
}
}
return dis[n];
}

spfa

 三.Floyd 算法:

  解决的问题:1.全局最短路。2.最长路

  思想:动态规划

  做法:对于每个节点k,都对定点对[i,j]做一次松弛操作

  算法复杂度:O(n^3)

  核心算法:

 for (int k=; k<n; ++k) {
for (int i=; i<n; ++i) {
for (int j=; j<n; ++j) {
/*
实际中为防止溢出,往往需要选判断 dist[i][k]和dist[k][j
都不是Inf ,只要一个是Inf,那么就肯定不必更新。
*/
if (dist[i][k] + dist[k][j] < dist[i][j] ) {
dist[i][j] = dist[i][k] + dist[k][j];
}
}
}
}

  说明:最短路的最优子结构(不只是对于Floyd,对于任何的最短路算法都有次性质)可以通过反证法证明,这里应用这个最优子结构的性质,来用Floyd算法来记录最短路的路径

 void floyd() {
for(int i=; i<=n ; i++){
for(int j=; j<= n; j++){
if(map[i][j]==Inf){
path[i][j] = -;//表示 i -> j 不通
}else{
path[i][j] = i;// 表示 i -> j 前驱为 i
}
}
}
for(int k=; k<=n; k++) {
for(int i=; i<=n; i++) {
for(int j=; j<=n; j++) {
if(!(dist[i][k]==Inf||dist[k][j]==Inf)&&dist[i][j] > dist[i][k] + dist[k][j]) {
dist[i][j] = dist[i][k] + dist[k][j];
path[i][k] = i;
path[i][j] = path[k][j];
}
}
}
}
}
void printPath(int from, int to) {
/*
* 这是倒序输出,若想正序可放入栈中,然后输出。
*
* 这样的输出为什么正确呢?个人认为用到了最优子结构性质,
* 即最短路径的子路径仍然是最短路径
*/
while(path[from][to]!=from) {
System.out.print(path[from][to] +"");
to = path[from][to];
}
}

当然,这里只是提供一个思路,其实对于所有的最短路保存路径都可以用类似是dfs保存路径的方法,通过保存前驱的方法,每次松弛操作的时候对前驱也进行修改就可以了

 【最小生成树问题】

解决最小生成树问题的算法有:prim算法和kruskal算法

一.prim 算法(普利姆算法)

  思想:贪心

  做法:类似于dijkstra算法,只不过是每次选取的点是距离生成树最近的点,更新的时候不再是更新这个点到起始点的最短距离,而是到这个生成输的最短距离。

  核心代码:

 void prim(int s , int n)
{
int i , j , k ;
for( i = ; i <= n ;i++)
{
p[i] = false;
dist[i] = mp[s][i];
}
p[s] = true;
dist[s] = ;
for(i = ; i < n ; i++)
{
int Min = INF;
int k = ;
for( j = ; j <= n ;j++)
{
if(!p[j]&&dist[j]<Min)
{
Min = dist[j];
k = j;
}
}
if(Min==INF) return ;
p[k] = true;
for(j = ; j <= n ;j++)
{
if(!p[j]&&mp[k][j]!=INF&&dist[j]>mp[k][j])
dist[j] = mp[k][j];
}
}
}

  时间复杂度:邻接矩阵:O(v^2)     邻接表:O(elog2v)

二.kruskal 算法

  思想:并查集

  做法:将原图G中所有E条边按权值从小到大排序。循环:从权值最小的边开始遍历每条边,直至图G_new中所有的节点都在同一个连通分量中。每次从图中未加入树种的边种找到边权最小的看,这两个点的祖先是否是一个,如果是一个说明两个点已经是一个树上的了,不做操作,如果两个点来自不同的树即有不同的祖先,那么就把这两个点所代表的两个树合并起来,最后当所有的点都在一棵树上的时候停止操作,一般用合并次数来控制,即n个点需要合并n-1次,所以最好合并操作写在kruskal函数内部,这样方便统计步数

  核心代码:

 struct Edge{
int from;
int to;
int w;
bool operator < (const Edge &a) const
{
return w<a.w;
}
}edge[N*N];
int fa[N];
int Getfa(int x){return (fa[x]==x)?x:fa[x] = Getfa(fa[x]); }
int fl;
int n,m;
bool solve(int x){
int cnt = ;//共合n-1次结束
for(int i = ; i <= n; i++) fa[i] = i;//注意点是从1开始编号的
for(int i = x; i < m; i++){
int X = Getfa(edge[i].from);
int Y = Getfa(edge[i].to);
if(X != Y){
fa[X] = Y;
cnt++;
if(cnt==n-){ fl = edge[i].w;return true;}
}
}
return false;
}

注意:对于图的题,一定要根据题意来选取是用链表存储还是用数组存储,选择好的存储方法便于解决问题,也要注意点的编号是从几开始的。

最小生成树&最短路基础算法总结的更多相关文章

  1. ACM基础算法入门及题目列表

    对于刚进入大学的计算机类同学来说,算法与程序设计竞赛算是不错的选择,因为我们每天都在解决问题,锻炼着解决问题的能力. 这里以TZOJ题目为例,如果为其他平台题目我会标注出来,同时我的主页也欢迎大家去访 ...

  2. 最小生成树两个经典算法(Prime算法、Kruskal算法) - biaobiao88

    经典的最小生成树例子,Prime算法,具体的步骤及其注释本人均在代码中附加,请仔细阅读与品味,要求,可以熟练的打出. //Prime算法基础 #include<iostream> usin ...

  3. PHP基础算法

    1.首先来画个菱形玩玩,很多人学C时在书上都画过,咱们用PHP画下,画了一半. 思路:多少行for一次,然后在里面空格和星号for一次. <?php for($i=0;$i<=3;$i++ ...

  4. 10个经典的C语言面试基础算法及代码

    10个经典的C语言面试基础算法及代码作者:码农网 – 小峰 原文地址:http://www.codeceo.com/article/10-c-interview-algorithm.html 算法是一 ...

  5. Java基础算法集50题

    最近因为要准备实习,还有一个蓝桥杯的编程比赛,所以准备加强一下算法这块,然后百度了一下java基础算法,看到的都是那50套题,那就花了差不多三个晚自习的时间吧,大体看了一遍,做了其中的27道题,有一些 ...

  6. 贝叶斯公式由浅入深大讲解—AI基础算法入门

    1 贝叶斯方法 长久以来,人们对一件事情发生或不发生的概率,只有固定的0和1,即要么发生,要么不发生,从来不会去考虑某件事情发生的概率有多大,不发生的概率又是多大.而且概率虽然未知,但最起码是一个确定 ...

  7. 图->连通性->最小生成树(普里姆算法)

    文字描述 用连通网来表示n个城市及n个城市间可能设置的通信线路,其中网的顶点表示城市,边表示两城市之间的线路,赋于边的权值表示相应的代价.对于n个定点的连通网可以建立许多不同的生成树,每一棵生成树都可 ...

  8. 贝叶斯公式由浅入深大讲解—AI基础算法入门【转】

    本文转载自:https://www.cnblogs.com/zhoulujun/p/8893393.html 1 贝叶斯方法 长久以来,人们对一件事情发生或不发生的概率,只有固定的0和1,即要么发生, ...

  9. java入门学习(3)—循环,选择,基础算法,API概念

    1.顺序结构:也就是顺着程序的前后关系,依次执行.2.选择分支:利用if..else , / switch(){case [ 这个必须是常量]:}; / if..else if….. ….else.. ...

随机推荐

  1. LeetCode中的最大子串和问题(Maximum Subarray)

    问题描述: Find the contiguous subarray within an array (containing at least one number) which has the la ...

  2. 三菱Q系列PLC的io分配

    1.系统基本配置 2.存储卡配置 3.外部IO标号 4.主基板IO模块的IO号分配 5.扩展基板IO口标号 6.标准配置实例 7. 一.输入采样阶段 在输入采样阶段,可编程逻辑控制器以扫描方式依次地读 ...

  3. 我是如何确认线上CLOSE_WAIT产生的原因及如何解决的。

    1.阐述 内部架构:Tomcat应用程序---> nginx ---> 其他Tomcat应用程序,内部Tomcat应用通过nginx调用其他应用. HTTP插件:HttpClient 4. ...

  4. Yum database disk image is malformed

    使用 yum update 时使用Ctrl+C 后,再用yum 安装其他软件的时候收到:Yum database disk image is malformedyum clean dbcache 清除 ...

  5. HTML基本功之文档结构

    项目名 首页 命名为 index.html 样式文件夹 命名为 css  /*用来放样式文件*/ base.css  /*基本样式*/ index.css /*首页样式*/ global.css /* ...

  6. sqlalchemy 踩过的坑

    记录下Sqlalchemy遇到的问题,不定时更新. 设置主键为非自增 sqlalchemy 在sql server中默认主键是自增的,如果在数据库设置的主键不是自增的,这个时候插入就会出现异常: 提示 ...

  7. unittest单元测试框架详解

    unittest单元测试框架不仅可以适用于单元测试,还可以适用WEB自动化测试用例的开发与执行,该测试框架可组织执行测试用例,并且提供了丰富的断言方法,判断测试用例是否通过,最终生成测试结果.今天笔者 ...

  8. angular4.0项目文件解读

    这篇文章我觉得是很有用的,便于我们对ng项目的理解,同时在配置项目时,也能够很快的定位到相应文件. 摘录的别人的文章,首先感谢那个路人兄弟,下面就开始学习吧. File 文件 Purpose 用途 e ...

  9. C盘里的桌面文件移到E盘里了,然后E盘里的文件都显示到桌面上了,怎么将桌面文件还原回C盘

    1 . 直接按Windows键+R,打开"运行"对话框,在输入框中输入"regedit"命令,会打开注册表编辑窗口: 2.打开注册表文件将HKEY_CURREN ...

  10. Mac操作系统下忘记MYSQL的密码

    1. 在系统偏好 中,中止MySQL服务.: 2. cd/usr/local/mysql/bin   sudo ./mysqld_safe --skip-grant-tables 3. 登录MySQL ...