最小生成树&最短路基础算法总结
【最短路问题】
解决最短路问题有以下算法: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;
}
注意:对于图的题,一定要根据题意来选取是用链表存储还是用数组存储,选择好的存储方法便于解决问题,也要注意点的编号是从几开始的。
最小生成树&最短路基础算法总结的更多相关文章
- ACM基础算法入门及题目列表
对于刚进入大学的计算机类同学来说,算法与程序设计竞赛算是不错的选择,因为我们每天都在解决问题,锻炼着解决问题的能力. 这里以TZOJ题目为例,如果为其他平台题目我会标注出来,同时我的主页也欢迎大家去访 ...
- 最小生成树两个经典算法(Prime算法、Kruskal算法) - biaobiao88
经典的最小生成树例子,Prime算法,具体的步骤及其注释本人均在代码中附加,请仔细阅读与品味,要求,可以熟练的打出. //Prime算法基础 #include<iostream> usin ...
- PHP基础算法
1.首先来画个菱形玩玩,很多人学C时在书上都画过,咱们用PHP画下,画了一半. 思路:多少行for一次,然后在里面空格和星号for一次. <?php for($i=0;$i<=3;$i++ ...
- 10个经典的C语言面试基础算法及代码
10个经典的C语言面试基础算法及代码作者:码农网 – 小峰 原文地址:http://www.codeceo.com/article/10-c-interview-algorithm.html 算法是一 ...
- Java基础算法集50题
最近因为要准备实习,还有一个蓝桥杯的编程比赛,所以准备加强一下算法这块,然后百度了一下java基础算法,看到的都是那50套题,那就花了差不多三个晚自习的时间吧,大体看了一遍,做了其中的27道题,有一些 ...
- 贝叶斯公式由浅入深大讲解—AI基础算法入门
1 贝叶斯方法 长久以来,人们对一件事情发生或不发生的概率,只有固定的0和1,即要么发生,要么不发生,从来不会去考虑某件事情发生的概率有多大,不发生的概率又是多大.而且概率虽然未知,但最起码是一个确定 ...
- 图->连通性->最小生成树(普里姆算法)
文字描述 用连通网来表示n个城市及n个城市间可能设置的通信线路,其中网的顶点表示城市,边表示两城市之间的线路,赋于边的权值表示相应的代价.对于n个定点的连通网可以建立许多不同的生成树,每一棵生成树都可 ...
- 贝叶斯公式由浅入深大讲解—AI基础算法入门【转】
本文转载自:https://www.cnblogs.com/zhoulujun/p/8893393.html 1 贝叶斯方法 长久以来,人们对一件事情发生或不发生的概率,只有固定的0和1,即要么发生, ...
- java入门学习(3)—循环,选择,基础算法,API概念
1.顺序结构:也就是顺着程序的前后关系,依次执行.2.选择分支:利用if..else , / switch(){case [ 这个必须是常量]:}; / if..else if….. ….else.. ...
随机推荐
- PHP (超文本预处理器)
PHP(外文名:PHP: Hypertext Preprocessor,中文名:"超为本预处理器")是一种通用开源脚本语言.语法吸收了C语言.java和Rerl的特点,利于学习,使 ...
- bzoj 4444: [Scoi2015]国旗计划
Description A国正在开展一项伟大的计划--国旗计划.这项计划的内容是边防战士手举国旗环绕边境线奔袭一圈.这 项计划需要多名边防战士以接力的形式共同完成,为此,国土安全局已经挑选了N名优秀的 ...
- PXE+Kickstart 全自动安装部署CentOS7.4
一.简介 1.什么是PXE PXE(preboot execute environment,预启动执行环境)是由Intel公司开发的最新技术,工作于Client/Server的网络模式,支持工作站通过 ...
- 闲来无事做了一个批处理的win10账号管理
@echo off %1 mshta vbscript:CreateObject("Shell.Application").ShellExecute("cmd.exe&q ...
- JMeter集合点
位置:添加--> 定时器-->Synchronizing Timer 注意:集合点放在所有操作之前. 假设线程组线程数设置的是50个,那么希望50个都准备好一块上,那么集合点中 ...
- java复写equals例子
public class users { String name; static int age; public boolean equals(Object obj) { if(this==obj){ ...
- Parallels Desktop 12
我微新solq123987654 备注:PD 科普:PD12有什么用,PD是让mac系统可以运行wind系统的软件,如果你不习惯mac os 或工作需要那PD绝对是个好软件正版要七八百授权,只要十五就 ...
- thinkinginjava学习笔记01_导论
初学java,希望旅途愉快 :) 类型决定对象的接口,(有人认为类是类型的特定实现),接口确定对象所能发出的请求(消息),满足请求的代码和隐藏的数据一起构成实现: 对象设计时,应该很好地完成一项任务 ...
- java中的位操作
之前做项目的时候使用位操作不是很多,今天在刷leetcode上题目的时候用到了位操作,是leetcode中的第29题Divide Two Integers. 一.java的位操作: 位运算表达式由操作 ...
- SqlServer Lock_Escalation
在今天的文章里,我想谈下SQL Server里锁升级(Lock Escalations).锁升级是SQL Server使用的优化技术,用来控制在SQL Server锁管理里把持锁的数量.我们首先用SQ ...