热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

分支定界算法求解带有约束条件的最短路径问题

知识点:分支定界;Dijkstra;c++读取txt文件到二维数组这个题目是北航研究生算法课的,因为以前主要写java,用c++写作业的时候遇到了一些读文件啊,深度优先遍历图的问题

知识点:分支定界; Dijkstra; c++读取txt文件到二维数组

这个题目是北航研究生算法课的,因为以前主要写java,用c++写作业的时候遇到了一些读文件啊,深度优先遍历图的问题啥的,所以记录下来。

题目:
Assignment 2
用分支定界算法求以下问题:
某公司于乙城市的销售点急需一批成品, 该公司成品生产基地在甲城市。甲城市与乙城市之间共有 n 座城市,互相以公路连通。甲城市、乙城市以及其它各城市之间的公路连通情况及每段公路的长度由矩阵M1 给出。每段公路均由地方政府收取不同额度的养路费等费用, 具体数额由矩阵 M2 给出。请给出在需付养路费总额不超过 1500 的情况下,该公司货车运送其产品从甲城市到乙城市的最短运送路线。
具体数据参见文件:
M1.txt: 各城市之间的公路连通情况及每段公路的长度矩阵(有向图); 甲城市为城市 Num.1,乙城市为城市 Num.50。
M2.txt: 每段公路收取的费用矩阵(非对称)。
点此下载可执行程序和源代码以及m1.txt,m2.txt

  • 主要思路:
    • 遍历:利用栈结构,通过深度优先搜索遍历路径
    • 定界:每一个最短路径值更小的可行解确定了新的下界
    • 剪枝:先利用Dijkstra算法计算每个城市到目的城市的最短路径和最小花费,当算法运行到某个城市后,计算在栈里的城市的路径长度 + 这个城市到目的城市的最短路径,以及在栈里的城市的路径花费 + 这个城市到目的地的最小花费, 与当前最优的可行解以及约束条件进行比较,从而达到剪枝的目的

平心而论,代码的一般……

代码:

// Assignment_2.cpp : Defines the entry point for the console application.
/*
* 主要思路:
* 遍历:利用栈结构,通过深度优先搜索遍历路径
* 定界:每一个最短路径值更小的可行解确定了新的下界
* 剪枝:先利用Dijkstra算法计算每个城市到目的城市的最短路径和最小花费,当算法运行到某个城市后,
* 计算在栈里的城市的路径长度 + 这个城市到目的城市的最短路径,以及在栈里的城市的路径花费 + 这个城市到目的地的最小花费,
* 与当前最优的可行解以及约束条件进行比较,从而达到剪枝的目的
*/


#include "stdafx.h"

#include
#include
#include
#include

using namespace std;

#define MAX_NODE 60 // 最大节点数
#define MAX_INT 9999 // 定义最大整数
#define MAX_COST 1500 // 定义最大花费

int n1, n2; // 分别表示矩阵的行和列
deque<int> queueMinPath; // 记录已得到的最短路径
int minPath; // 记录最短路径长度
int costOfMinPath; // 记录最短路径的花费

int main(int argc, char* argv[]) {

clock_t startTime, endTime;
startTime = clock();

cout <"程序开始运行" <
int** readTxtToArrayWithoutKnowRowOrColumn(const char* strPath); // 把txt文件读进二维数组
void findPathWithDFS(int **m1, int **m2, int fn, int tn); // 深度优先

int pIn[MAX_INT] = { 0 }; // 记录某个城市是否在当前路径

int** m1 = 0, **m2 = 0; // 分别保存m1.txt和m2.txt的矩阵

cout <<"从txt文件读取数据(请把txt文件和可执行文件放在同一路径下):" <
m1 = readTxtToArrayWithoutKnowRowOrColumn("m1.txt");

m2 = readTxtToArrayWithoutKnowRowOrColumn("m2.txt");

cout <<"行数: " <", 列数: " <
for (int i = 0; i for (int j = 0; j if (m1[i][j] == MAX_INT) {
m2[i][j] = MAX_INT;
}
}
}

minPath = MAX_INT;
findPathWithDFS(m1, m2, 0, n1 - 1);

cout <<"满足条件的最短路径长度为: " < cout <<"满足条件的最短路径的花费为: " < cout <<"最短路径为: " < for (int is = 0; is cout <<"\t" <1;
}
cout <
cout <<"程序运行结束" < endTime = clock();
cout <<"总共耗时: " <<(double)(endTime - startTime) / CLOCKS_PER_SEC <<" 秒" <
cout <<"按 即可退出程序" < getchar();

return 0;
}

void findPathWithDFS(int **m1, int **m2, int fn, int tn) {
int calculateShortestByDijkstra(int **m1, int fn, int tn); // 根据a矩阵计算从fn到tn的最短距离或者最小花费
int p1[MAX_NODE] = { 0 }, c1[MAX_NODE] = { 0 }; // 分别保存各个城市到目的地的最短路径和最小花费
int pMin = MAX_INT, cNow = MAX_INT; // 分别记录当前到的路径的最小路径长度和当前花费

cout <<"先用Dijkstra算法求出每个城市到目的城市的最短路径和最小花费" < // 各个城市到达目的城市的最短路径
for (int i = 0; i p1[i] = calculateShortestByDijkstra(m1, i, n1 - 1);
}
// 各个城市到达目的城市的最小花费
for (int i = 0; i c1[i] = calculateShortestByDijkstra(m2, i, n1 - 1);
}

cout <<"再用分枝定界算法求满最大花费不超过" <"的最短路径" < deque<int> stackPathNode;
stackPathNode.push_back(fn);
int nPath[MAX_NODE] = { 0 };
nPath[fn] = 1;
int lastOut = -1;
int tag = 0; // 标记是否找到下一个城市
int pathLengthNow = 0; // 当前已经走到的路径长度
int pathCostNow = 0; // 当前已经走到的路径的花费
int nNow;
while (!stackPathNode.empty()) { // 栈为空
nNow = stackPathNode.back();
for (int i = 0; i if (nPath[i] == 1 || i <= lastOut || nPath[i] == 1)
continue;
if (m1[nNow][i] // 根据当前能够获取的最短路径长度和最小花费确定是否剪枝
if (pathLengthNow + p1[i] >= minPath || pathCostNow + c1[i] > MAX_COST) {
// 当前路径的最优解没有已有的可行解好,或者当前路径的最小花费超过 MAX_COST
continue;
}
if (pathLengthNow + m1[nNow][i] >= minPath || pathCostNow + m2[nNow][i] > MAX_COST){
continue;
}
if (i == tn) {
// 找到一条更好的路径,如下
minPath = pathLengthNow + m1[nNow][i];
costOfMinPath = pathCostNow + m2[nNow][i];
pathLengthNow = minPath;
pathCostNow = costOfMinPath;
stackPathNode.push_back(i);
queueMinPath = stackPathNode;
break;

}
else {
// 当前城市有下一个城市可以寻得最优解,下一个城市入栈
tag = 1;
stackPathNode.push_back(i);
nPath[i] = 1;
pathLengthNow += m1[nNow][i];
pathCostNow += m2[nNow][i];
lastOut = -1;
break;
}
}

}

if (tag == 0) {
// 当前城市没有下一个城市可以寻得最优解,当前城市出栈
lastOut = stackPathNode.back();
stackPathNode.pop_back();
if (stackPathNode.empty()) {
break;
}
nNow = stackPathNode.back();
nPath[lastOut] = 0;
pathLengthNow -= m1[nNow][lastOut];
pathCostNow -= m2[nNow][lastOut];
}
tag = 0;
}
}

int** readTxtToArrayWithoutKnowRowOrColumn(const char* strPath) { // 把txt文件读进二维数组
int** a = new int*[MAX_NODE];
for (int i = 0; i a[i] = new int[MAX_NODE];
}
int nTmp = 0;
n1 = 0;
n2 = 0;
ifstream is(strPath);
if (!is) {
cout <<"open file error!" < }
else {
char p;
int num;
int j = 0;
while (is.get(p)) { // 判断是否到达文末
do {
if (p == '\n') {
n1++; // 统计行数
if (n2 == 0) {
n2 = nTmp; // 实际上只统计了第一行的列数
}
j = 0;
// cout <
}
} while (isspace((int)p) && is.get(p));
if (!is)
break;
nTmp++; // 统计列数
is.putback(p); // 如果前面读入的不是空格或者回车符,则把刚才读入的字符返回文件流
is >> num;
// cout <
a[n1][j++] = num;
}
}
is.close();
return a;
}

int calculateShortestByDijkstra(int **m1, int fn, int tn) { // 根据距离矩阵计算从fn到tn的最短距离或者最小花费

if (fn == tn) {
return 0;
}

int p[MAX_NODE] = { 0 }; // 记录当前路径长度
int pt[MAX_NODE] = { 0 }; // 记录当前路径是否是最短路径,1表示是

for (int i = 0; i if (i != fn)
p[i] = MAX_INT;
}

p[fn] = 0; // nf到nf的路径为0
pt[fn] = 1; // 当前nf到nf的路径是最短路径

for (int i = 0; i 1
; i++) { // 求n个节点中1个节点到另一个节点的最短路径最多需要n-1步
for (int j = 0; j if (pt[j] != 1) {
// 还没有求出第nf第j个节点的最短路径
for (int k = 0; k // 计算nf到第j个节点的路径
if (pt[k] == 1) {
// k是已经求出最短路径的节点
if (m1[k][j] // 如果k到j有路径
if ((p[k] + m1[k][j]) p[j] = p[k] + m1[k][j];
}
}
}

}
}
}

int tmp = MAX_INT;
for (int j = 0; j if (pt[j] != 1) {
if (p[j] tmp = p[j];
}
}
}

for (int j = 0; j if (pt[j] != 1) {
if (p[j] == tmp) {
pt[j] = 1;
if (j == tn) {
return p[j];
}
}
}
}
}

return -1;
}


推荐阅读
  • 本文介绍了深入浅出Linux设备驱动编程的重要性,以及两种加载和删除Linux内核模块的方法。通过一个内核模块的例子,展示了模块的编译和加载过程,并讨论了模块对内核大小的控制。深入理解Linux设备驱动编程对于开发者来说非常重要。 ... [详细]
  • Linux环境变量函数getenv、putenv、setenv和unsetenv详解
    本文详细解释了Linux中的环境变量函数getenv、putenv、setenv和unsetenv的用法和功能。通过使用这些函数,可以获取、设置和删除环境变量的值。同时给出了相应的函数原型、参数说明和返回值。通过示例代码演示了如何使用getenv函数获取环境变量的值,并打印出来。 ... [详细]
  • vue使用
    关键词: ... [详细]
  • 本文讨论了使用差分约束系统求解House Man跳跃问题的思路与方法。给定一组不同高度,要求从最低点跳跃到最高点,每次跳跃的距离不超过D,并且不能改变给定的顺序。通过建立差分约束系统,将问题转化为图的建立和查询距离的问题。文章详细介绍了建立约束条件的方法,并使用SPFA算法判环并输出结果。同时还讨论了建边方向和跳跃顺序的关系。 ... [详细]
  • 动态规划算法的基本步骤及最长递增子序列问题详解
    本文详细介绍了动态规划算法的基本步骤,包括划分阶段、选择状态、决策和状态转移方程,并以最长递增子序列问题为例进行了详细解析。动态规划算法的有效性依赖于问题本身所具有的最优子结构性质和子问题重叠性质。通过将子问题的解保存在一个表中,在以后尽可能多地利用这些子问题的解,从而提高算法的效率。 ... [详细]
  • 本文介绍了PE文件结构中的导出表的解析方法,包括获取区段头表、遍历查找所在的区段等步骤。通过该方法可以准确地解析PE文件中的导出表信息。 ... [详细]
  • 本文介绍了一个题目的解法,通过二分答案来解决问题,但困难在于如何进行检查。文章提供了一种逃逸方式,通过移动最慢的宿管来锁门时跑到更居中的位置,从而使所有合格的寝室都居中。文章还提到可以分开判断两边的情况,并使用前缀和的方式来求出在任意时刻能够到达宿管即将锁门的寝室的人数。最后,文章提到可以改成O(n)的直接枚举来解决问题。 ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • 本文介绍了最长上升子序列问题的一个变种解法,通过记录拐点的位置,将问题拆分为左右两个LIS问题。详细讲解了算法的实现过程,并给出了相应的代码。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • Webpack5内置处理图片资源的配置方法
    本文介绍了在Webpack5中处理图片资源的配置方法。在Webpack4中,我们需要使用file-loader和url-loader来处理图片资源,但是在Webpack5中,这两个Loader的功能已经被内置到Webpack中,我们只需要简单配置即可实现图片资源的处理。本文还介绍了一些常用的配置方法,如匹配不同类型的图片文件、设置输出路径等。通过本文的学习,读者可以快速掌握Webpack5处理图片资源的方法。 ... [详细]
  • 本文介绍了一种划分和计数油田地块的方法。根据给定的条件,通过遍历和DFS算法,将符合条件的地块标记为不符合条件的地块,并进行计数。同时,还介绍了如何判断点是否在给定范围内的方法。 ... [详细]
  • 本文介绍了在Vue项目中如何结合Element UI解决连续上传多张图片及图片编辑的问题。作者强调了在编码前要明确需求和所需要的结果,并详细描述了自己的代码实现过程。 ... [详细]
  • C++字符字符串处理及字符集编码方案
    本文介绍了C++中字符字符串处理的问题,并详细解释了字符集编码方案,包括UNICODE、Windows apps采用的UTF-16编码、ASCII、SBCS和DBCS编码方案。同时说明了ANSI C标准和Windows中的字符/字符串数据类型实现。文章还提到了在编译时需要定义UNICODE宏以支持unicode编码,否则将使用windows code page编译。最后,给出了相关的头文件和数据类型定义。 ... [详细]
  • 3.223.28周学习总结中的贪心作业收获及困惑
    本文是对3.223.28周学习总结中的贪心作业进行总结,作者在解题过程中参考了他人的代码,但前提是要先理解题目并有解题思路。作者分享了自己在贪心作业中的收获,同时提到了一道让他困惑的题目,即input details部分引发的疑惑。 ... [详细]
author-avatar
n大牙
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有