分支限界法 tsp java_基于分支限界法的旅行商问题(TSP)一

//分支限界法

#include#include#include#include

const int INF = 100000;const int MAX_N = 22;using namespacestd;//n*n的一个矩阵

intn;int cost[MAX_N][MAX_N];//最少3个点,最多MAX_N个点

structNode

{bool visited[MAX_N];//标记哪些点走了

int s;//第一个点

int s_p;//第一个点的邻接点

int e;//最后一个点

int e_p;//最后一个点的邻接点

int k;//走过的点数

int sumv;//经过路径的距离

int lb;//目标函数的值(目标结果)

bool operator

}

};

priority_queue pq;//创建一个优先队列

int low, up;//下界和上界

bool dfs_visited[MAX_N];//在dfs过程中搜索过//确定上界,利用dfs(属于贪心算法),贪心法的结果是一个大于实际值的估测结果

int dfs(int u, int k, int l)//当前节点,目标节点,已经消耗的路径

{if (k == n) return l + cost[u][1];//如果已经检查了n个节点,则直接返回路径消耗+第n个节点回归起点的消耗

int minlen =INF, p;for (int i = 1; i <= n; i++)

{if (!dfs_visited[i] && minlen > cost[u][i])//取与所有点的连边中最小的边

{

minlen= cost[u][i];//找出对于每一个节点,其可达节点中最近的节点

p =i;

}

}

dfs_visited[p]= true;//以p为下一个节点继续搜索

return dfs(p, k + 1, l +minlen);

}voidget_up()

{

dfs_visited[1] = true;//以第一个点作为起点

up = dfs(1, 1, 0);

}//用这种简单粗暴的方法获取必定小于结果的一个值

voidget_low()

{//取每行最小值之和作为下界

low = 0;for (int i = 1; i <= n; i++)

{//创建一个等同于map的临时数组,可用memcpy

inttmpA[MAX_N];for (int j = 1; j <= n; j++)

{

tmpA[j]=cost[i][j];

}

sort(tmpA+ 1, tmpA + 1 + n);//对临时的数组进行排序

low += tmpA[1];

}

}intget_lb(Node p)

{int ret = p.sumv * 2;//路径上的点的距离的二倍

int min1 = INF, min2 = INF;//起点和终点连出来的边

for (int i = 1; i <= n; i++)

{//cout << p.visited[i] << endl;

if (!p.visited[i] && min1 >cost[i][p.s])

{

min1=cost[i][p.s];

}//cout << min1 << endl;

}

ret+=min1;for (int i = 1; i <= n; i++)

{if (!p.visited[i] && min2 >cost[p.e][i])

{

min2=cost[p.e][i];

}//cout << min2 << endl;

}

ret+=min2;for (int i = 1; i <= n; i++)

{if (!p.visited[i])

{

min1= min2 =INF;for (int j = 1; j <= n; j++)

{if (min1 >cost[i][j])

min1=cost[i][j];

}for (int j = 1; j <= n; j++)

{if (min2 >cost[j][i])

min2=cost[j][i];

}

ret+= min1 +min2;

}

}return (ret + 1) / 2;

}intsolve()

{//贪心法确定上界

get_up();//取每行最小的边之和作为下界//cout << up << endl;//test

get_low();//cout << low << endl;//test//设置初始点,默认从1开始

Node star;

star.s= 1;//起点为1

star.e = 1;//终点为1

star.k = 1;//走过了1个点

for (int i = 1; i <= n; i++)

{

star.visited[i]= false;

}

star.visited[1] = true;

star.sumv= 0;//经过的路径距离初始化

star.lb = low;//让目标值先等于下界

int ret = INF;//ret为问题的解

pq.push(star);//将起点加入队列

while(pq.size())

{

Node tmp=pq.top();pq.pop();if (tmp.k == n - 1)//如果已经走过了n-1个点

{//找最后一个没有走的点

intp;for (int i = 1; i <= n; i++)

{if (!tmp.visited[i])

{

p= i;//让没有走的那个点为最后点能走的点

break;

}

}int ans = tmp.sumv + cost[p][tmp.s] + cost[tmp.e][p];//已消耗+回到开始消耗+走到P的消耗//如果当前的路径和比所有的目标函数值都小则跳出

if (ans <=tmp.lb)

{

ret=min(ans, ret);break;

}//否则继续求其他可能的路径和,并更新上界

else{

up= min(up, ans);//上界更新为更接近目标的ans值

ret =min(ret, ans);continue;

}

}//当前点可以向下扩展的点入优先级队列

Node next;for (int i = 1; i <= n; i++)

{if (!tmp.visited[i])

{//cout << "test" << endl;

next.s = tmp.s;//沿着tmp走到next,起点不变

next.sumv = tmp.sumv + cost[tmp.e][i];//更新路径和

next.e = i;//更新最后一个点

next.k = tmp.k + 1;//更新走过的顶点数

for (int j = 1; j <= n; j++) next.visited[j] = tmp.visited[j];//tmp经过的点也是next经过的点

next.visited[i] = true;//自然也要更新当前点//cout << next.visited[i] << endl;

next.lb = get_lb(next);//求目标函数//cout << next.lb << endl;

if (next.lb > up) continue;//如果大于上界就不加入队列

pq.push(next);//否则加入队列//cout << "test" << endl;

}

}//cout << pq.size() << endl;BUG:测试为0

}returnret;

}intmain()

{

cin>>n;for (int i = 1; i <= n; i++)

{for (int j = 1; j <= n; j++)

{

cin>>cost[i][j];if (i ==j)

{

cost[i][j]=INF;

}

}

}

cout<< solve() <

}/*测试

5

100000 5 61 34 12

57 100000 43 20 7

39 42 100000 8 21

6 50 42 100000 8

41 26 10 35 100000

36

请按任意键继续. . .*/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/334524.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

苹果录屏功能没有声音_其实苹果手机也有录屏功能!简单操作几步,就能轻松开启...

现在手机中的娱乐方式越来越多了&#xff0c;大家遇到有趣的事情就想分享给朋友&#xff0c;但是一些视频不能直接分享链接&#xff0c;还是挺麻烦的。不过我们可以通过录屏的方式来进行分享的&#xff0c;其实苹果手机就自带录屏工具&#xff0c;简单操作几步&#xff0c;就能…

Linux 启动/重启/停止 MySQL 数据库的命令

文章目录一、启动 MySQL 数据库的命令&#xff08;一&#xff09;使用命令 service 启动&#xff08;二&#xff09;使用命令 systemctl 启动二、停止 MySQL 数据库的命令&#xff08;一&#xff09;使用命令 service 停止&#xff08;二&#xff09;使用命令 systemctl 停止&a…

natty的异步通信框架_OpenHub框架进行的异步通信

natty的异步通信框架在本系列的前一部分中&#xff0c;我们介绍了OpenHub框架 。 这部分显示了框架最强大的功能之一- 异步消息传递模型 。 当源系统无法等待目标系统的响应时&#xff0c;将使用系统之间的异步通信。 有以下几个原因&#xff1a; 源系统必须尽可能地响应 &am…

java大文件解析_java大文件(百M以上)的上传下载实例解析

javaweb上传文件上传文件的jsp中的部分上传文件同样可以使用form表单向后端发请求&#xff0c;也可以使用 ajax向后端发请求1.通过form表单向后端发送请求Save改进后的代码不需要form标签&#xff0c;直接由控件来实现。开发人员只需要关注业务逻辑即可。JS中已经帮我们封闭好了…

zip直链生成网站_安装网站程序

一、选择网站程序搭建网站的程序有很多博客类&#xff1a; WordPress、 Typecho 、Hexo 等商城类&#xff1a;EcShop、DBShop、NiuShop 等论坛类&#xff1a;Discuz 还有 苹果CMS-影视建站&#xff1b;Tipask-问答程序&#xff1b;可道云KodExplorer-强大易用的私有云/在线文档…

java jni开发_Java JNI开发实践记录

当使用到JNI的时候&#xff0c;基本可以肯定Java的平台移植性注定减弱&#xff0c;接下来记录一次使用Java JNI开发的经历。关于Java JNI的相关资料参见&#xff1a;下面是使用JNI常见三种场景:1.在Java应用中标准Java类库不支持平台相关的特性2.已经存在用其它语言写好的类库&…

Linux 系统服务管理(启动服务/停止服务/重启服务)的命令 - chkconfig/service/systemctl

文章目录一、使用命令 chkconfig 管理系统服务&#xff08;一&#xff09;命令介绍二、使用命令 service 管理系统服务&#xff08;一&#xff09;命令介绍&#xff08;二&#xff09;命令用法1.启动服务2.停止服务3.重启服务4.查看状态三、使用命令 systemctl 管理系统服务一、…

mega x_[MEGA DEAL]通过Hadoop Bundle掌握大数据(91%的折扣)

mega x通过44个小时的广泛Hadoop培训来驯服海量数据集 嘿&#xff0c;怪胎&#xff0c; 本周&#xff0c;在我们的JCG Deals商店中 &#xff0c;我们提供了另一个超值优惠 。 通过Hadoop Bundle&#xff0c;我们可以提供91&#xff05;的 大数据精通 折扣 。 现在只需39美元…

c++ 提取傅里叶描述子_AI大语音(四)——MFCC特征提取(深度解析)

1 特征提取流程在语音识别和话者识别方面&#xff0c;最常用到的语音特征就是梅尔倒谱系数&#xff08;Mel-scaleFrequency Cepstral Coefficients&#xff0c;简称MFCC&#xff09;。MFCC提取过程包括预处理、快速傅里叶变换、Mei滤波器组、对数运算、离散余弦变换、动态特征提…

Linux 命令之 grep -- 强大的文本搜索工具/正则表达式搜索

文章目录一、命令介绍二、grep 的三种形式三、常用选项四、正则表达式五、参考示例在指定的文件中查找指定的关键词查看指定文件中含有特定关键词的文本行查看指定文件中所有包含数字的行在指定的目录下递归搜索指定的字符串&#xff0c;将符合的文本行及其文件名输出在指定文件…

java me基础教程 pdf_Java ME手机应用开发技术与案例详解 PDF

资源名称&#xff1a;Java ME手机应用开发技术与案例详解 PDFJava ME手机应用开发技术与案例详解基于Java ME&#xff0c;系统描述了Java ME手机应用开发的各个方面。全书按照Java ME程序的开发流程合理编排内容&#xff0c;分成3个部分依次讲述。第1部分包括第1章-第5章&#…

cli parser_Java命令行界面(第27部分):cli-parser

cli parserCLI Parser最初托管在Google Code上&#xff0c;现在已存档在Google Code上 &#xff0c;现在可以在GitHub上使用 。 Google Code项目档案页面将CLI Parser描述为“使用非常简单&#xff0c;非常小的依赖项”&#xff0c;它使用注释“使非常简洁的主要方法不需要知道…

写一个sql实现以下查询结果_书写高质量SQL的30条建议

以下文章来源&#xff1a;后端程序员必备&#xff1a;书写高质量SQL的30条建议1、查询SQL尽量不要使用select *&#xff0c;而是select具体字段。反例子&#xff1a;select * from employee;正例子&#xff1a;select id&#xff0c;name from employee;理由&#xff1a;只取需…

Linux 命令之 sed -- 功能强大的流式文本编辑器

文章目录一、命令介绍二、命令格式三、常用选项四、sed 子命令五、sed 替换标记六、sed 元字符集七、命令示例&#xff08;一&#xff09;用指定的字符串替换掉指定的字符串&#xff08;二&#xff09;删除文档中的空白行&#xff08;三&#xff09;删除文档中的注释&#xff0…

flatmap_flatMap()与concatMap()与concatMapEager()– RxJava常见问题解答

flatmapRxJava 2.x中共有三个无缝相似的运算符&#xff1a; flatMap() &#xff0c; concatMap()和concatMapEager() 。 它们都接受相同的参数-从原始流的单个项目到任意类型的&#xff08;子&#xff09;流的函数。 换句话说&#xff0c;如果您有Flowable<T>则可以为任意…

java 中的点_java————形参中的点点点 | 学步园

转自:http://zhidao.baidu.com/question/149668626.htmlmain方法的签名其实可以这样写:public static void main(String... args)//方法1它也可以运行.并且,如果同时还存在public static void main(String[] args)//方法2会报已经存在重复的方法的错误.由此可见,String... args…

sendkeys.send 始终输出英文._PLC的三种输出方式,你知道有哪些吗?

电工技术维修学习网&#xff1a;www.dgjswx.com关注电工技术维修学习网官方微信公众号《电工维修学习》收获更多电工经验知识和提升实战技能电工技术&#xff0c;电气知识&#xff0c;电工基础知识&#xff0c;电工入门知识&#xff0c;电工资料&#xff0c;电工软件&#xff0…

Linux 命令之 echo -- 输出指定的字符串或者变量的值

文章目录一、命令介绍二、命令选项三、命令示例&#xff08;一&#xff09;输出变量的值&#xff08;二&#xff09;合并上下单元格内容&#xff08;三&#xff09;查看一行第一栏&#xff08;四&#xff09;查看一行的第一和第三栏&#xff08;五&#xff09;结合输出重定向符…

java 死循环排查_java应用死循环排查方法或查找程序消耗资源的线程方法(面试)...

今天遇到一个面试&#xff0c;怎么在一堆线程中查找一个死循环&#xff1f;如果遇到线上应用cpu飙升&#xff0c;并出现OutOfMemery怎么办&#xff1f;首先线上应用的jvm配置要养成良好的习惯&#xff0c;增加一下配置则可以在jvm发生 oom的时候自动dump日志了 -XX:HeapDumpOn…

jw摄像_Java命令行界面(第17部分):jw-options

jw摄像JavaWorld的文章“ 用Java处理命令行参数”&#xff1a; Matthias Laux博士关闭的案例介绍了一个简单的基于Java的库&#xff0c;用于处理命令行参数 &#xff0c;我在本文中将其称为jw-options 。 被引用的文章提供了有关为何在构造Options类时做出某些设计决策的背景信…