Floyd算法 多源最短路径

解决稠密图较好

  1. 准备工作
#include <iostream>		//Floyd算法解决稠密图时更好
#include <algorithm>
#include <climits>
#include <cstring>
using namespace std;
const int MaxV = 100;
/*定义边*/
typedef struct ENode{
	int v1, v2;
	int Weight;
} * Edge;
/*定义邻接矩阵存储的图*/
typedef struct GNode{
	int Nv, Ne;
	int W[MaxV][MaxV];	//权重
	//string Data[MaxV];
	int Dist;
} * MGraph;
/*图的初始化*/
MGraph CraeteGraph(int Nv)
{
	MGraph G = new GNode;
	G->Nv = Nv; G->Ne = 0;
	memset(G->W, 0x3f, sizeof(G->W));	//初始化为无穷大,同时要保证无穷大 + 无穷大 还是无穷大
	for (int i = 0; i < G->Nv; i++)
		G->W[i][i] = 0;
	return G;
}
void InsertEdge(MGraph G, Edge E)
{
	G->W[E->v1][E->v2] = E->Weight;
	G->W[E->v2][E->v1] = E->Weight;
}

MGraph BuildGraph()
{
	int Nv; cin >> Nv;
	MGraph G = CraeteGraph(Nv);
	cin >> G->Ne;
	Edge E = new ENode;
	for (int i = 0; i < G->Ne; i++)
	{
		cin >> E->v1 >> E->v2 >> E->Weight;
		InsertEdge(G, E);
	}
	delete E;
	return G;
}
  1. 核心算法
//dp问题dp(k)[i][j]表示: 从i到j的最短路径,k == -1时,表示直接i到j的最短路径, k表示计算的步骤
//状态转换方程: dp(k)[i][j] = min{dp(k - 1)[i][j], dp(k - 1)[i][k] + dp(k - 1)[k][j]}
void Folyd(MGraph G, int dp[][MaxV], int path[][MaxV])
{
	/*初始化数组*/
	for (int i = 0; i < G->Nv; i++)
		for (int j = 0; j < G->Nv; j++)
		{
			dp[i][j] = G->W[i][j];
			path[i][j] = -1;
		}

	/*dp填表过程*/
	for (int k = 0; k < G->Nv; k++)
		for (int i = 0; i < G->Nv; i++)
			for (int j = 0; j < G->Nv; j++)
				if(dp[i][j] > dp[i][k] + dp[k][j])
				{
					dp[i][j] = dp[i][k] + dp[k][j];
					path[i][j] = k;
				}
}
void Serch_path(MGraph G, const int path[][MaxV], int i, int j)
{
	if(path[i][j] == -1)
	{
		G->Dist += G->W[i][j];	//统计最短路径
		cout << "->" << j;
		return;
	}

	Serch_path(G, path, i, path[i][j]);
	Serch_path(G, path, path[i][j], j);
}
void Print(MGraph G, const int path[][MaxV], int i, int j)
{
	G->Dist = 0;
	cout << i;
	Serch_path(G, path, i, j);
	cout << " Dist=" << G->Dist;
	cout << endl;
}

int main()
{
	int dp[MaxV][MaxV];
	int path[MaxV][MaxV];
	cout << "输入有向图:" << endl;
	MGraph G = BuildGraph();
	Folyd(G, dp, path);
	int start, end;
	while (1)
	{
		cout << "输入起点和终点:" << endl;
		cin >> start >> end;
		if(start == -1 && end == -1)
			break;
		else if(start >= 0 && start < G->Nv && end >= 0 && end < G->Nv)
			Print(G, path, start, end);
		else
			cout << "数据不合法" << endl;
	}
	delete G;
	system("pause");
	return 0;
}
  1. 运行结果
输入有向图:
10 17
0 1 2
1 2 5
1 3 2
0 3 5
2 4 8
2 5 4
3 5 4
3 6 2
4 5 2
5 6 3
4 7 5
5 7 9
5 8 6
6 8 7
7 8 3
7 9 4
8 9 8
输入起点和终点:
0 9
0->1->3->5->4->7->9 Dist=19
输入起点和终点:
9 0
9->7->4->5->3->1->0 Dist=19
输入起点和终点:
9 4
9->7->4 Dist=9
输入起点和终点:
2 2
2->2 Dist=0
输入起点和终点:
651 231
数据不合法
输入起点和终点:
-1 -1
请按任意键继续. . .
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值