实验四单源最短路径问题
一、实验目的:
1、理解分支限界法的剪枝搜索策略;
2、掌握分支限界法的算法柜架;
3、掌握分支限界法的算法步骤;
4、通过应用范例学习动态规划算法的设计技巧与策略;
二、实验内容及要求:
1、使用分支限界法解决单源最短路径问题。
2、通过上机实验进行算法实现。
3、保存和打印出程序的运行结果,并结合程序进行分析,上交实验报告。
三、实验原理:
分支限界法的基本思想:
1、分支限界法与回溯法的不同:
1)求解目标:回溯法的求解目标是找出解空间树中满足约束条件的所有解,而分支限界法的求解目标则是找出满足约束条件的一个解,或是在满足约束条件的解中找出在某种意义下的最优解。
2)搜索方式的不同:回溯法以深度优先的方式搜索解空间树,而分支限界法则以广度优先或以最小耗费优先的方式搜索解空间树。
2、分支限界法基本思想:
分支限界法常以广度优先或以最小耗费(最大效益)优先的方式搜索问题的解空间树。
在分支限界法中,每一个活结点只有一次机会成为扩展结点。
活结点一旦成为扩展结点,就一次性产生其所有儿子结点。
在这些儿子结点中,导致不可行解或导致非最优解的儿子结点被舍弃,其余儿子结点被加入活结点表中。
此后,从活结点表中取下一结点成为当前扩展结点,并重复上述结点扩展过程。
这个过程一直持续到找到所需的解或活结点表为空时为止。
3、常见的两种分支限界法:
1)队列式(FIFO)分支限界法
按照队列先进先出(FIFO)原则选取下一个节点为扩展节点。
2)优先队列式分支限界法
按照优先队列中规定的优先级选取优先级最高的节点成为当前扩展节点。
四、程序代码
#include<iostream>
using namespace std;
int matrix[100][100]; // 邻接矩阵
bool visited[100]; // 标记数组
int dist[100]; // 源点到顶点i的最短距离
int path[100]; // 记录最短路的路径
int source; // 源点
int vertex_num; // 顶点数
int edge_num; // 边数
int destination; // 终结点
void Dijkstra(int source)
{
memset(visited, 0, sizeof(visited)); // 初始化标记数组
visited[source] = true;
for (int i = 0; i < vertex_num; i++)
{
dist[i] = matrix[source][i];
path[i] = source;
}
int min_cost; // 权值最小
int min_cost_index; // 权值最小的下标
for (int i = 1; i < vertex_num; i++) // 找到源点到另外 vertex_num-1 个点的最短路径{
min_cost = INT_MAX;
for (int j = 0; j < vertex_num; j++)
{
if (visited[j] == false && dist[j] < min_cost) // 找到权值最小
{
min_cost = dist[j];
min_cost_index = j;
}
}
visited[min_cost_index] = true; // 该点已找到,进行标记
for (int j = 0; j < vertex_num; j++) // 更新 dist 数组
{
if (visited[j] == false &&
matrix[min_cost_index][j] != INT_MAX && // 确保两点之间有边
matrix[min_cost_index][j] + min_cost < dist[j])
{
dist[j] = matrix[min_cost_index][j] + min_cost;
path[j] = min_cost_index;
}
}
}
}
int main()
{
cout << "请输入图的顶点数(<100):";
cin >> vertex_num;
cout << "请输入图的边数:";
cin >> edge_num;
for (int i = 0; i < vertex_num; i++)
for (int j = 0; j < vertex_num; j++)
matrix[i][j] = (i != j) ? INT_MAX : 0; // 初始化 matrix 数组cout << "请输入边的信息:\n";
int u, v, w;
for (int i = 0; i < edge_num; i++)
{
cout << "请输入第" << i + 1 << "条边的信息(中间用空格隔开):";
cin >> u >> v >> w;
matrix[u][v] = matrix[v][u] = w;
}
cout << "请输入源点(<" << vertex_num << "):";
cin >> source;
Dijkstra(source);
cout << "请输入终结点(<" << vertex_num << "):";
cin >> destination;
cout << source << "到" << destination << "最短距离是:" << dist[destination] << ",路径是:" << destination;
int t = path[destination];
while (t != source)
{
cout << "<--" << t;
t = path[t];
}
cout << "<--" << source << endl;
return 0;
}
五、结果运行与分析
本例用使迪杰斯特拉算法来求单源最短路径,也即采用优先队列式分支限界法,按照优先队列中规定的优先级选取优先级最高的节点成为当前扩展节点。
选定源节点后,从源节点开始扩展,并将其子节点按路径长度大小依次存于栈中,每次从栈顶弹出节点作为扩展节点,利用限界来剪去相应的节点。
六、心得与体会
通过这次实验,对迪杰斯特拉算法求解单源最短路径问题做了回顾,上学期修数据结构是已经了解,但是时间长了没有练习就基本忘记了,通过这次实验,更加深了对该算法的印象,也对动态规划做了回顾。
本次实验最重要的还是分支限界法,使用限界,可以有效减小工作量,提高效率。