Folyd + 路径存储
一、Folyd 算法原理

- 如果 AB + AC < BC 那么, BC最短路就要经过 A。 在算法进行过程中,应该是
,B-A 有很多路径,B 代表这些路径权值之和,A-C也有很多路径,C是这些权值之和。那么我们找到一个 满足 AB + AC < BC 的时候更新权值数组,并且记录路径。 dist[i][j] = k 表示,从 I -- J 点的路径权值为 K
记录路径,就是将 C 点连接在 B A C 这样的路径后

二、简单容易理解版
核心代码:
//邻接矩阵保存点信息
int mapp[MAX_POINT][MAX_POINT];
//保存任意两点之间的最短路径上的节点
vector<int> trace_path[MAX_POINT][MAX_POINT]; void Folyd(int n) {
for (int k = ; k < n; k++)
for (int i = ; i < n; i++)
for (int j = ; j < n; j++)
if (mapp[i][j] > mapp[i][k] + mapp[k][j]) {
mapp[i][j] = mapp[i][k] + mapp[k][j];
trace_path[i][j].clear();
//放入 i---k 路径节点
for (int z = ; z < trace_path[i][k].size(); z++)
trace_path[i][j].push_back(trace_path[i][k][z]);
//放入 k---j 路径节点
for (int z = ; z < trace_path[k][j].size(); z++)
trace_path[i][j].push_back(trace_path[k][j][z]);
}
} void query(int from, int to) {
cout << "from " << from << " to " << to << " should cost " << mapp[from][to] <<"."<< endl;
cout << "trace_path: " ;
for (int i = ; i < trace_path[from][to].size(); i++)
cout<< trace_path[from][to][i] << " -> ";
cout << to << endl;
}
上述代码中:存在重复存储,效率极低
trace_path[i][j].clear();
//放入 i---k 路径节点
for (int z = ; z < trace_path[i][k].size(); z++)
trace_path[i][j].push_back(trace_path[i][k][z]);
//放入 k---j 路径节点
for (int z = ; z < trace_path[k][j].size(); z++)
trace_path[i][j].push_back(trace_path[k][j][z]);
优化代码:
由于上面代码每次都重复把点的信息都保存下来,因此,我们采用保存前驱几点的方式,最终通过回溯构建路径。
path[i][j] = k ; //表示 从 i---j 路径中, k 是 j 的直接前驱, 那么最短路径 1->5->4->3->6 有 paht[1][6] = 3; paht[1][3]= 4; paht[1][4] = 5; paht[1][5] =1 如此逆推不难得到 最短路径记录值
核心代码:
//邻接矩阵保存点信息
int mapp[MAX_POINT][MAX_POINT];
//path[i][j] = k ,表示从 i 到 j 最短路, k 邻接到j。
int path[MAX_POINT][MAX_POINT];
void Folyd(int n) {
//初始化路径数组
for (int i = ; i < n; i++)
for (int j = ; j < n; j++) {
if (mapp[i][j] - INF)
path[i][j] = i;
else
path[i][j] = NOTEXISTS;
} for (int k = ; k < n; k++)
for (int i = ; i < n; i++)
for (int j = ; j < n; j++)
if (mapp[i][j] > mapp[i][k] + mapp[k][j]) {
mapp[i][j] = mapp[i][k] + mapp[k][j];
//path[i][j] = k; //这种思路中,不能写成这样
path[i][j] = path[k][j];
}
} void print_path(int from, int to) {
if (path[from][to] != from)
print_path(from, path[from][to]);
cout << " -> " << to;
}
在更改权值的时候,即使记录下来当前点的前驱节点。 path[i][j] = path[k][j]; 切不可以写成,path[i][j] = k; 后者是另一种思路,下面会描述。path[i][j] = path[k][j] 达到 j 节点 的前驱节点修改为经过k到j的路径上去。
完整代码:
测试数据:
-

1. 基础版本
//Folyd
#include <iostream>
#include <vector>
#include <algorithm> using namespace std; const int INF = 0x3f3f3f3f;
const int MAX_POINT = ; //邻接矩阵保存点信息
int mapp[MAX_POINT][MAX_POINT];
//保存任意两点之间的最短路径上的节点
vector<int> trace_path[MAX_POINT][MAX_POINT]; void Folyd(int n) {
for (int k = ; k < n; k++)
for (int i = ; i < n; i++)
for (int j = ; j < n; j++)
if (mapp[i][j] > mapp[i][k] + mapp[k][j]) {
mapp[i][j] = mapp[i][k] + mapp[k][j];
trace_path[i][j].clear();
//放入 i---k 路径节点
for (int z = ; z < trace_path[i][k].size(); z++)
trace_path[i][j].push_back(trace_path[i][k][z]);
//放入 k---j 路径节点
for (int z = ; z < trace_path[k][j].size(); z++)
trace_path[i][j].push_back(trace_path[k][j][z]);
}
} void query(int from, int to) {
cout << "from " << from << " to " << to << " should cost " << mapp[from][to] <<"."<< endl;
cout << "trace_path: " ;
for (int i = ; i < trace_path[from][to].size(); i++)
cout<< trace_path[from][to][i] << " -> ";
cout << to << endl;
} int main(int argc, char const *argv[])
{
int n;
cout << "Please input gragh points:";
cin >> n;
//init container, 自己到自己默认 0,其他为 INF
for (int i = ; i < n; i++) {
mapp[i][i] = ;
for (int j = ; j < n; j++)
if (i != j)
mapp[i][j] = INF;
} int t = (n*(n - )) >> ;
// 最多输入 n(n -1)>>1 条边
cout << "Please input edges format a tuple (f, t , v), to end input via (-1, 0, 0)" << endl;
while (--t > ) {
int from, to, value;
cin >> from >> to >> value;
if (~from) {
//无向图
mapp[from][to] = value;
mapp[to][from] = value;
//每条路的前驱放入路径中
trace_path[from][to].push_back(from);
trace_path[to][from].push_back(to);
}
else
break;
} Folyd(n); //结果打表
cout << "====================" << endl;
for (int i = ; i < n; i++) { for (int j = ; j < n; j++)
cout << mapp[i][j] << "\t";
cout << endl;
}
cout << "====================" << endl;
while(){
int beginP, endP;
cout << "Please input begin point and end point:";
cin >> beginP >> endP;
query(beginP, endP);
}
return ;
}
2. 改进版本
//Folyd
//输入图,可以不连通
#include <iostream>
using namespace std; const int INF = 0x3f3f3f3f;
const int MAX_POINT = ;
const int NOTEXISTS = ~(0U); //邻接矩阵保存点信息
int mapp[MAX_POINT][MAX_POINT];
//path[i][j] = k ,表示从 i 到 j 最短路, k 邻接到j。
int path[MAX_POINT][MAX_POINT];
void Folyd(int n) {
//初始化路径数组
for (int i = ; i < n; i++)
for (int j = ; j < n; j++) {
if (mapp[i][j] - INF)
path[i][j] = i;
else
path[i][j] = NOTEXISTS;
} for (int k = ; k < n; k++)
for (int i = ; i < n; i++)
for (int j = ; j < n; j++)
if (mapp[i][j] > mapp[i][k] + mapp[k][j]) {
mapp[i][j] = mapp[i][k] + mapp[k][j];
path[i][j] = path[k][j];
}
} void print_path(int from, int to) {
if (path[from][to] != from)
print_path(from, path[from][to]);
cout << " -> " << to;
} int main(int argc, char const *argv[])
{
int n;
cout << "Please input gragh points:";
cin >> n; //init container
for (int i = ; i < n; i++) {
mapp[i][i] = ; //自己到自己默认 0
for (int j = ; j < n; j++)
if (i != j)
mapp[i][j] = INF;
} int t = (n*(n - )) >> ;
// 最多输入 n(n -1)>>1 条边
cout << "Please input edges format a tuple (f, t , v), to end input via (-1, 0, 0)" << endl;
while (--t > ) {
int from, to, value;
cin >> from >> to >> value;
if (~from) {
mapp[from][to] = value;
mapp[to][from] = value;
}
else
break;
}
Folyd(n); cout << "====================" << endl;
for (int i = ; i < n; i++) { for (int j = ; j < n; j++)
cout << mapp[i][j] << "\t";
cout << endl;
}
cout << "====================" << endl;
while () {
int beginP, endP;
cout << "Please input begin point and end point:";
cin >> beginP >> endP;
//print path
cout << "from " << beginP << " to " << endP << " should cost " << mapp[beginP][endP] << "." << endl;
if (path[beginP][endP] == NOTEXISTS)
cout << "No path!" << endl;
else {
cout << "trace_path: ";
cout << beginP;
print_path(beginP, endP);
cout << endl;
}
}
return ;
}
参考资料:
https://blog.csdn.net/start0609/article/details/7779042
https://blog.csdn.net/immiao/article/details/22199939
Folyd + 路径存储的更多相关文章
- DM 多路径存储
DM多路径存储 系统环境:RHEL5.4 small install selinux and iptables disabled主机规划:主机网卡软件station133eth0: 192.168. ...
- photoshop:把路径存储为形状
这个其实跟定义画笔步骤是一样的 路径存储为自定义形状 1.用路径选择工具(快捷键A),选中路径 2.菜单:编辑->定义自定形状 3.选择自定义形状工具(快捷键U),可以看到刚定义的形状 把当前形 ...
- RHEL 6.5----iscsi多路径存储
主机名 IP master eth0: 192.168.30.130(NAT) eth1: 192.168.17.130(VMNet4) node-1 eth0: 192.168.30.131(NAT ...
- ASP.Net 5 上传文件通过虚拟路径存储
先贴上代码 [HttpPost] public IActionResult ImportTeaching(IFormFile file) { string root = @"Temp/tea ...
- express实现前后端通信上传图片,存储数据库(mysql)傻瓜教程(三)完结篇
终于完成了所有自己想要的功能(鼓励下自己),虽然还是很简陋,但是还是挺有满足感的,哈哈. 附上前两篇的链接: 第一篇 第二篇 进入正题,在第二篇里面已经完成了连接数据库,并且实现了对数据库的增删改查, ...
- HTML5 LocalStorage 本地存储的用法
本地存储变量b的值: localStorage.setItem("b","isaac"); 本地获取变量b的值: localStorage.getItem(&q ...
- 【转】mysql保存图片技术决定:保存二进制文件还是只保存图片相对路径,图片放在硬盘上面?
最近遇到上面这个问题,一开始我就果断否决了数据库保存图片的策略,主要是太蠢!事实上我的决定是正确的,我仅仅理解为mysql读写性能提高的境界,具体为什么可以提高?很模糊,知道我看到了这里: 大佬做的实 ...
- Windows system 在python文件操作时的路径表示方法
file_path =(r'i:\vacpy\ch10\pi_digits.txt') #将文件路径存储在变量file_path中with open (file_path) as file_objec ...
- 多路径multipath配置,udev绑定
多路径multipath配置 以root用户登录 1.查看共享磁盘是否挂载成功 #fdisk -l 2.生成配置文件 #mpathconf --enable 修改配置文件权限 #chmod 644 / ...
随机推荐
- Java 使用Log4J进行日志操作
使用Log4J进行日志操作 Log4J简介 Log4J是Apache的一个开放源代码项目,它是一个日志操作包,通过使用Log4J,可以指定日志信息输出的目的地,如控制台.文件.CUI组件.NT ...
- arcgis10.sp5下载地址
http://support.esrichina.com.cn/2012/0716/1649.html
- C++类继承--构造函数时先构造基类
以下说明继承类函数构造时,先构造基类: 析构基类时,若没加上virtual,只析构基类,不析构派生类: 析构派生类时,同时会析构基类: 1. 基类析构函数有virtual #include <s ...
- python完全学习笔记
dir(__builtins__) help(input) 'let\'s go' #转义字符 \ r'c:\now' #字符串前加r 自动转义 str= ''' shdiufhi s ...
- 如何一次性下载某个类库依赖的所有jar包"
** 经常碰到这种事情: ** 在一些非maven工程中(由于某种原因这种工程还是手工添加依赖的),需要用到某个新的类库(假设这个类库发布在maven库中),而这个类库又间接依赖很多其他类库,如果依赖 ...
- Linux 内核超时导致虚拟机无法正常启动
问题描述 当 Linux 虚拟机启动时,通过串口输出或者启动日志, 观察到超时的报错.导致虚拟机无法正常启动和连接. 问题分析 常见的超时报错范例如下: 复制 INFO: task swapper:1 ...
- 查询组成员(group)
查询组成员 $groupname = "groupname" $members = (get-adgroup $groupname -properties member).memb ...
- vue-cli中自定义路径别名 assets和static文件夹的区别
转自:vue-cli中自定义路径别名 assets和static文件夹的区别 静态资源处理: assets和static文件夹的区别 相信有很多人知道vue-cli有两个放置静态资源的地方,分别是sr ...
- Python+Selenium2自动化测试之IE、chrome浏览器启动
构建Python+Selenium2自动化测试环境完成之后,就需要测试支持python的selenium的版本是否都支持在不同浏览器上运行,当前我们分别在三个最通用的浏览器上通过脚本来测试. 1.在I ...
- Linux中nmon的安装与使用
一.下载nmon. 根据CPU的类型选择下载相应的版本:http://nmon.sourceforge.net/pmwiki.php?n=Site.Downloadwget http://source ...