Dijkstra、Dij + heap、Floyd、SPFA、 SPFA + SLF Template

Dijkstra in Adjacency matrix :


int Dijkstra(int src,int tec, int n){
bool done[1005];
int d[1005];
memset(done,0,sizeof(done));

map[0][src] = 0;//巧妙之处,加入超级源点0

for(int i = 0;i <= n;i++)
d[i] = (i == src ? 0 : 1000000);
for(int i = 0;i <= n;i++){//最多执行n+1次操作
int minx,minn = 1000000;
for(int j = 0;j <= n;j++)//先找到d[]最小的点
if(!done[j] && d[j] < minn){
minn = d[j];
minx = j;
}
done[minx] = 1;//将该点加入集合
if(minx == ter) return d[minx];
for(int j = 0;j <= n;j++){//再更新所有的d[]
if(!done[j] && d[minx] + map[minx][j] < d[j]){
d[j] = d[minx] + map[minx][j];
}
}
}
return -1;//如果没有找到到终点的路径,返回-1
}


Dijkstra in Adjacency list :


int dijkstra(int src,int ter){//src源点,ter终点
vist[src] = 1;
dist[src] = 0;
for(int i = head[src];i != -1;i = edge[i].pre ){
dist[edge[i].cur] = edge[i].w; //dist[x]保存从源点到节点x当前最短距离
}
for(int i = 1;i < n;i ++){
int cur = 0,Min = inf;
for(int j = 1;j <= n;j ++){
if(!vist[j] && dist[j] < Min){
Min = dist[j];
cur = j;
}
}
vist[cur] = 1;
if(cur == ter) return dist[cur];
//当ter被标记为访问过时,说明当前dist[ter]已经为src到ter的最短距离
for(int j = head[cur];j != -1;j = edge[j].pre ){
int to = edge[j].cur;
if(!vist[to]){
dist[to] = min(dist[to],dist[cur] + edge[j].w);
}
}
}
return dist[ter];
}


Dijkstra + heap :


int dijkstra(int src,int ter){
vist[src] = 1;
dist[src] = 0;
priority_queue<node>q;
/*
struct node{
int v,dist;//顶点和距离
node(int vv,int ddist){v=vv,dist=ddist;}
bool operator<(const node &A)const{return dist > A.dist;}//最小优先
};
*/
q.push(node(src,0));
int cur = src;
for(int i = 0;i < n;i ++){
for(int j = head[cur];j != -1;j = edge[j].pre ){
int to = edge[j].cur;
if(!vist[to] && dist[to]>dist[cur]+edge[j].w){
dist[to] = dist[cur] + edge[j].w;
q.push(node(to,dist[to]));
}
}
while(!q.empty()&&vist[q.top().v]){
q.pop();
}
cur = q.top().v;q.pop();
vist[cur] = 1;
if(cur == ter)break;
}
return dist[ter];
}


Floyd :

简单描述一下Floyd:首先我们需要一个邻接矩阵

(所谓邻接矩阵是一个 n*n 的矩阵, 第i行第j列的值为value 表示i点到j点的距离为value

.若i到j点不可达时我们可以使value=inf)

注意传递闭包的概念, 得到一个传递闭包至多将任意两点松弛n次。

第一层for是用k点去松弛, 第二层和第三层for是对于任意两点i、j。


#define inf 1000000000
// init***************
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
dp[i][j] = inf;
//****************
//--------------Floyd:
for(int k = 1; k <= n; k++)
for(int i = 1; i <= n; i++)if(i!=k && dp[i][k] != inf)
for(int j = 1; j <= n; j++)if(j!=i && j!=k)
dp[i][j] = min(dp[i][j], dp[i][k] + dp[k][j]);
//--------------
for(int i = 1; i <= n; i++) dp[i][i] = 0;


 SPFA:

1、注意对于最短路中存在负权判定:对于spfa算法

当某个点入队列(入队列的意义就是该点被松弛了(更新))次数>n次,

就说明该点在负权上(可以简单证明一个点至多被更新n次(n为图中的顶点数))。

2、优先队列:出队的元素不是在队尾的元素,

而是队列中最小的元素(我们有时可以在队列中存储结构体元素,只需重载运算符即可)。

?





1

2

3

4

5

struct
node{

    int
x, y;

    bool
operator<(const
node&a) const

    { if(a.x==x) return
a.y<y;  return
a.x<x; } //根据x,y值比较node结构体的大小

};

3、状态压缩:当某些状态只有true or false,时我们可以用一个整数来表示这个状态。

示例:

有3块不同的蛋糕编号1、2、3, 被老鼠啃过, 那么蛋糕只有2种状态, 我们用0表示没有被啃过, 1表示被啃过。

显然我们可以得到所有状态:000、001、010、011、100、101、110、111.

而上述二进制数对应的整数为 [0, 2^3) . (如二进制011 = 整数3表示
第2、3块蛋糕被啃过,第一块蛋糕没有被啃过)

我们可以用 for(int i = 0; i < (1<<3); i++) 来遍历所有的状态。

把多个事物的状态利用二进制含义压缩为一个整数称为状态压缩。

4、利用优先队列优化最短路时, 我们可以先出队距离起点最近的点, 则若出队的为终点显然我们已经得到了一条最短路了。


SPFA in Adjacency list :


int spfa(){
//for(int i=src;i<=ter;i++) dis[i]=-INF;
queue<int>q;
q.push(src);
vis[src]=1;
dis[src]=0;
while(!q.empty()){
int u=q.front();
q.pop();
vis[u]=0;
for(int i=head[u]; i!=-1; i=Edge[i].next){
int v=Edge[i].v;
if(dis[v]<dis[u]+Edge[i].val){
dis[v]=dis[u]+Edge[i].val;
if(!vis[v]){
vis[v]=1;
q.push(v);
}
}
}
}
return dis[ter];
}


SPFA + SLF in Adjacency list :


int spfa(int src,int ter){
//for(int i=src;i<=ter;i++) dis[i]=-INF;
deque<int>q;
q.push_back(src);
vis[src] = 1;//标记当前顶点是否在队列中
dis[src] = 0;
while(!q.empty()){
int u = q.front();
q.pop_front();
vis[u] = 0;
for(int i = head[u];i != -1;i = Edge[i].next){
int v = Edge[i].v;
if(dis[v] < dis[u] + Edge[i].val){//松弛
dis[v] = dis[u] + Edge[i].val;
if(!vis[v]){
vis[v] = 1;
if(!q.empty()&&dis[v]<dis[q.front()])//SLF优化
q.push_front(v);
else q.push_back(v);
}
}
}
}
return dis[ter];
}

时间: 2024-10-20 13:31:03

Dijkstra、Dij + heap、Floyd、SPFA、 SPFA + SLF Template的相关文章

poj 1860 Currency Exchange (SPFA、正权回路 bellman-ford)

链接:poj 1860 题意:给定n中货币,以及它们之间的税率,A货币转化为B货币的公式为 B=(V-Cab)*Rab,其中V为A的货币量, 求货币S通过若干此转换,再转换为原本的货币时是否会增加 分析:这个题就是判断是否存在正权回路,可以用bellman-ford算法,不过松弛条件相反 也可以用SPFA算法,判断经过转换后,转换为原本货币的值是否比原值大... bellman-ford    0MS #include<stdio.h> #include<string.h> str

Linux内存管理(text、rodata、data、bss、stack&amp;heap)

一.各内存区段的介绍 系统内的程序分为程序段和数据段,具体又可细分为一下几个部分: (1)text段-代码段 text段存放程序代码,运行前就已经确定(编译时确定),通常为只读,可以直接在ROM或Flash中执行,无需加载到RAM. 在嵌入式开发中,有时为了特别的需求(例如加速),也可将某个模块搬移到RAM中执行. (2)rodata段(read-only-data)-常量区 rodata段存储常量数据,比如程序中定义为const的全局变量,#define定义的常量,以及诸如"Hello Wor

内存管理概述、内存分配与释放、地址映射机制(mm_struct, vm_area_struct)、malloc/free 的实现

http://blog.csdn.net/pi9nc/article/details/23334659 注:本分类下文章大多整理自<深入分析linux内核源代码>一书,另有参考其他一些资料如<linux内核完全剖析>.<linux c 编程一站式学习>等,只是为了更好地理清系统编程和网络编程中的一些概念性问题,并没有深入地阅读分析源码,我也是草草翻过这本书,请有兴趣的朋友自己参考相关资料.此书出版较早,分析的版本为2.4.16,故出现的一些概念可能跟最新版本内核不同.

47 监控系统基础及zabbix介绍、zabbix工作原理及安装配置、zabbix on CentOS7、zabbix配置

02    zabbix工作原理及安装配置 配置环境 node1192.168.1.120CentOS6.7 node2192.168.1.121CentOS6.7 1.安装配置zabbix #安装前准备 [[email protected] ~]#yum -y install mysql-server mysq [[email protected] ~]# mysql mysql> CREATE DATABASE zabbix CHARACTER SET utf8; mysql> GRANT

解读微信质变、解读张小龙的七大价值观、解读领导艺术

微信张小龙简介: 伟大的.光荣的.正确的双料创始人.Foxmail创始人和微信创始人. 一般能成为"创始",那肯定其产品在一段时间广受大家欢迎和使用,并深入用户心灵,在同行业内起到标杆作用.三者去一不可,1)受欢 2)为用户着想 3)标杆. "创始"还不够,还得是人.一般像我这种货色天天弄篇水文,弄个电子读物,也只能自称"XX文章系列"撰写"者"."者"和"人"区别很大,往往后者能被后世

java中常用的包、类、以及包中常用的类、方法、属性-----io包

由于最近有需要,所以下面是我整理的在开发中常用的包.类.以及包中常用的类.方法.属性:有需要的看看 java中常用的包.类.以及包中常用的类.方法.属性 常用的包 java.io.*; java.util.*; java.lang.*; java.math.*; java.sql.*; java.text.*; java.awt.*; javax.swing.*;   包名 接口 类 方法 属性 java.io.*; java.io.Serializable实现序列化 java.io.Buffe

大学毕业必须知道的东西:三方协议、报到证(派遣证)、干部身份

[档案问题] 毕业之前必看的东西-你自己的档案问题,详细至极真正能证明你学习经历的就是你的档案.档案里面有你各个时期的学籍卡.成绩单.各方面的评语.获奖证明.还有你的党团材料.这些都是原始材料,不可复制. 档案虽然"光辉不再",但并不等于是随处可丢弃的"鸡肋", 专家建议:应届生应关心自己的档案,免得未来不必要的麻烦. [档案与工龄] 很多大学毕业生找到工作后,没有及时办理参加工作手续,工作几年后仍然是学生身份,从而影响了自己的转正定级,也影响到工龄和退休金的计算.

「Unity」与iOS、Android平台的整合:3、导出的Android-Studio工程

本文属于「Unity与iOS.Android平台的整合」系列文章之一,转载请注明出处. Unity默认导出的是Android-Eclipse工程,毕竟Eclipse for Android开发在近一两年才开始没落,用户量还是非常巨大的. 个人认为AndroidStudio非常好用,能轻易解决很多Eclipse解决不了或者很难解决的问题. 所以我将Unity导出的Andoid工程分为Eclipse和AndroidStudio两部分. 不过我之后的相关内容都会使用AndroidStudio,希望依然

整理之DOM事件阶段、冒泡与捕获、事件委托、ie事件和dom模型事件、鼠标事件

整理之DOM事件阶段 本文主要解决的问题: 事件流 DOM事件流的三个阶段 先理解流的概念 在现今的JavaScript中随处可见.比如说React中的单向数据流,Node中的流,又或是今天本文所讲的DOM事件流.都是流的一种生动体现.用术语说流是对输入输出设备的抽象.以程序的角度说,流是具有方向的数据. 事件流分事件冒泡与事件捕获 在浏览器发展的过程中,开发团队遇到了一个问题.那就是页面中的哪一部分拥有特定的事件? 可以想象画在一张纸上的一组同心圆,如果你把手指放在圆心上,那么你的手指指向的其