您的位置:首页 > 其它

最短路径---Floyd-Warshall,Dijkstra,Bell-man

2018-02-07 21:02 393 查看
Floyd-Warshall的基本思想: 通过一个中转点不断地来松弛顶点的出边

//Floyd-Warshall算法核心语句
for (int k = 1; k <= V; k++)
for (int i = 1; i <= V; k++)
for (int j = 1; j <= V; j++)
if ( e[i][j] > e[i][k] + e[k][j] ) e[i][j] = e[i][k] + e[k][j]


/*
*最短路径---Floyd-Warshall算法
*2018/2/7
*/
#include <bits/stdc++.h>
using namespace std;

const int maxn = 101;
const int inf = 10001;

int e[maxn][maxn], V, E;

void pf() {
for (int i = 1; i <= V; i++) {
for (int j = 1; j <= V; j++) {
cout << e[i][j] << " ";
}
cout << endl;
}
}

int main() {

int dis, t1, t2, t3;

//录入顶点和边的个数
cin >> V >> E;

//初始化邻接矩阵
for (int i = 1; i <= V; i++)
for (int j = 1; j <= V; j++)
if ( i == j ) e[i][j] = 0; //自己到自己的距离为0
else e[i][j] = inf; //否则为无穷大

//录入边
for (int i = 1; i <= E; i++) {
cin >> t1 >> t2 >> t3;
e[t1][t2] = t3;
}

//利用Floyd-Warshall算法算出最短路径
//       k为中转点
for (int k = 1; k <= V; k++ ) {
for (int i = 1; i <= V; i++) {
for (int j = 1; j <= V; j++) {
dis = e[i][k] + e[k][j]; //记录利用中转点后i到j的距离
if ( dis < e[i][j] ) {
e[i][j] = dis;
pf();
system("pause");
}
}
}
}
/**
4 8
1 2 2
1 3 6
1 4 4
2 3 3
3 1 7
3 4 1
4 1 5
4 3 12
**/
return 0;
}


Dijkstra的基本思想:找到已知最短路径的顶点,利用该顶点不断地松弛顶点的出边

/*
*最短路径---Dijkstra算法
*2018/2/7
*/
#include <bits/stdc++.h>
using namespace std;

const int maxn = 101;
const int inf = 10001;

int e[maxn][maxn], dis[maxn], book[maxn], V, E;

void pf() {
for (int i = 1; i <= V; i++) {
for (int j = 1; j <= V; j++) {
cout << e[i][j] << " ";
}
cout << endl;
}
}

int main() {

int t1, t2, t3, n;
int minsub, min_e;

//录入顶点和边的个数
cin >> V >> E;

//初始化邻接矩阵
for (int i = 1; i <= V; i++)
for (int j = 1; j <= V; j++)
if ( i == j ) e[i][j] = 0; //自己到自己的距离为0
else e[i][j] = inf; //否则为无穷大

//录入边
for (int i = 1; i <= E; i++) {
cin >> t1 >> t2 >> t3;
e[t1][t2] = t3;
}

//输入需要求最短路径的顶点
cin >> n;

//初始化dis数组,该数组表示n号顶点到其余顶点的初始距离
for (int i = 1; i <= V; i++)
dis[i] = e
[i];

//初始化book数组,用来标记该顶点有没有被使用过
for (int i = 1; i <= V; i++)
book[i] = 0;
book
= 1;

//Dijkstra算法核心语句
for (int i = 1; i <= V - 1; i++) {
//找到离顶点n最近的点
min_e = inf;
for (int j = 1; j <= V; j++) {
if ( book[j] == 0 && dis[j] < min_e ) {
min_e = dis[j];
minsub = j;
}
}
book[minsub] = 1;
for (int j = 1; j <= V; j++) {
if ( dis[j] > dis[minsub] + e[minsub][j] )
dis[j] = dis[minsub] + e[minsub][j];
}
}

//打印顶点n到各个顶点的最短路径
for (int i = 1; i <= V; i++)
cout << dis[i] << " ";
/**
6 9
1 2 1
1 3 12
2 3 9
2 4 3
3 5 5
4 3 4
4 5 13
4 6 15
5 6 4
1
*/
return 0;
}

Bell-man:
/*
*最短路径---Bellman(表男)算法
*2018/2/7
*/
#include <bits/stdc++.h>
using namespace std;

const int maxe = 1001, maxv = 1001, inf = 10001;
struct edge {
int from, to, cost;
};

int dis[maxv], V, E;
edge e[maxe];

int main() {

bool check = true; //用于判断是否需要继续松弛
int n;

//输入顶点与边的个数
cin >> V >> E;

//录入边
for (int i = 1; i <= E; i++)
cin >> e[i].from >> e[i].to >> e[i].cost;

//输入要求最短路径的顶点
cin >> n;

//初始化dis数组
for (int i = 1; i <= V; i++)
dis[i] = inf;
dis
= 0;

//表男算法核心语句
for (int i = 1; i <= V - 1 && check == true; i++) {
check = false;
for (int j = 1; j <= E; j++)
if ( dis[e[j].to] > dis[e[j].from] + e[j].cost ) {
cout << dis[e[j].to] << " " << dis[e[j].from] << " " << dis[e[j].cost] << endl;
dis[e[j].to] = dis[e[j].from] + e[j].cost;
check = true;
}
}

//检测负权回路
for (int i = 1; i <= E; i++)
if ( dis[e[i].to] > dis[e[i].from] + e[i].cost ) {
cout << "该图存在负权回路" << endl;
break;
}

//输出结果
for (int i= 1; i <= V; i++)
cout << dis[i] << " ";

return 0;

}

显然,Bellman算法是可以进行优化的,因为每一次实施松弛操作后,就会有一些顶点已经求得了其最短路,此后这些顶点的最短路的估计值就会一直保持不变,不再收到后续松弛操作的影响,但是每次仍需要判断是否需要松弛,所以浪费了时间.所以我们每次仅对最短路估计值发生变化了的顶点的所有出边执行松弛操作.

8fff
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: