实验五:分枝限界法
【实验目的】
应用分枝限界法的算法设计思想求解单源最短路径问题。
【实验内容与要求】
采用分支限界法编程求源点0到终点6的最短路径及其路径长度。
要求完成:⑴算法描述⑵写出程序代码⑶完成调试⑷进行过程与结果分析。
【实验性质】
在完成的过程中注意与回溯算法思想的比较,重点注意两种算法思想各自的特点以及实现方式比较。此实验的性质为综合性实验。
【算法思想及处理过程】
算法思想:
创建一个优先队列,用于存放待扩展的节点,初始时将起始节点加入队列中。
初始化起始节点的距离为0,其他节点的距离为无穷大。
不断从优先队列中取出节点,并将其标记为已扩展。然后遍历该节点的相邻节点,更新其距离和前驱节点。
如果通过扩展节点能够获得更短的距离,则更新该节点的距离和前驱节点。
将更新后的节点加入优先队列中。
重复步骤3,直到优先队列为空。
完成后,可以输出从起始节点到其他节点的最短路径及距离。
处理过程:
输入图的节点个数和边的数量。
创建邻接矩阵表示图,并初始化距离数组和前驱节点数组。
调用ShorestPaths函数,传入起始节点的索引。
在ShorestPaths函数中,创建一个优先队列,首先将起始节点加入优先队列中。
循环执行以下步骤:
从优先队列中取出一个节点。
遍历该节点的相邻节点,更新其距离和前驱节点。
如果更新后的节点不在优先队列中,则将其加入队列中。
输出从起始节点到各节点的最短路径及距离。
【程序代码】
#include <iostream>
#include<queue>
using namespace std;
#define MAX 99
struct Node {
int length; //权值
int i; //结点编号
friend bool operator <(Node a, Node b)
{
return a.length > b.length;
}
};
class Graph
{
public:
void ShorestPaths(int);
void ShowDist();
Graph();
~Graph();
private:
int n;
int* prev;
int** c;
int* dist;
};
Graph::Graph()
{
int wi = 0;
int yi = 0;
int s;
int i, j, m;
cout << "请输入图的节点个数:";
cin >> n;
cout << "请输入图的边的条数:";
cin >> s;
c = new int* [n];
for (wi = 0; wi < n; wi++)
{
c[wi] = new int[n];
}
dist = new int[n];
prev = new int[n];
for (wi = 0; wi < n; wi++)
{
for (yi = 0; yi < n; yi++)
{
c[wi][yi] = MAX;
}
}
cout << "请输入图的边( i,j,c[i,j] ) " << endl;
for (wi = 1; wi <= s; wi++)
{
cin >> i >> j >> m;
c[i][j] = m;
}
for (wi = 0; wi < n; wi++)
{
dist[wi] = MAX;
prev[wi] = 0;
}
prev[0] = 0;
}
Graph::~Graph()
{
for (int i = 0; i < n; i++)
delete[]c[i];
delete[]c;
delete[]dist;
delete[]prev;
}
void Graph::ShowDist()
{
cout << endl << "从源点到各节点的最短路径:" << endl;
int i = 0;
int temp = 0;
for (i = 0; i < n; i++)
{
cout << "dist[" << i << "] = " << dist[i] << endl;
}
cout << "从源点到终点的最短路径长度为:" << dist[n - 1] << endl;
cout << "其路径为:";
temp = n - 1;
while (temp >= 0)
{
if (prev[temp] == 0 && temp == 0)
{
cout << temp;
break;
}
else
{
cout << temp << "->";
}
temp = prev[temp];
}
cout << endl;
}
void Graph::ShorestPaths(int v)
{
priority_queue<Node> H; //定义优先队列(最小堆)
Node E; //扩展节点
E.i = v;
E.length = 0;
dist[v] = 0;
cout << "当前扩展节点:" << E.i << ",权重:" << E.length << endl;
while (true)
{
int j;
for (j = 0; j < n; j++)
{
if ((c[E.i][j] != MAX) && (c[E.i][j] != 0))
{
if (E.length + c[E.i][j] < dist[j])
{
dist[j] = E.length + c[E.i][j];
prev[j] = E.i;
if (j != n - 1)
{
Node N;
N.i = j;
N.length = dist[j];
H.push(N); //N结点入队
cout << "入队结点:" << N.i << ",权重:" << N.length << endl;
}
}
}
} //for
if (!H.empty())
{
E = H.top();//出队
cout << "出队:" << E.i << endl;
H.pop(); //删除該元素
cout << endl << "下一个扩展节点:" << E.i << ",权重:" << E.length << endl;
}
else
break;
} //while
}
int main()
{
Graph g;
g.ShorestPaths(0);
g.ShowDist();
return 0;
}
【运行结果】
自行运行截图
【算法分析】
算法分析: Dijkstra算法的时间复杂度为O(n^2),其中n为节点的个数。由于使用了优先队列H来优化算法,堆的插入和删除操作的时间复杂度为O(logn),因此总的时间复杂度为O(nlogn)。
空间复杂度为O(n^2),主要是二维数组c的空间和堆的空间。