穷举法、回溯法、分支界限法解决旅行商(TSP)问题

文章目录

  • 一、问题描述
  • 二、穷举法解决
    • 2.1 介绍
    • 2.2 代码
  • 三、回溯法解决
  • 四、分支界限法
    • 4.1 介绍
    • 4.2 代码


一、问题描述

 有一个旅行商由某城市出发,经过所有给定的 n n n 个城市后,再回到出发的城市。除了出发的城市外,其它城市只经过一回。这样的回路可能有多个,求其中路径成本最小的回路。

二、穷举法解决

2.1 介绍

 穷举法的本质是全排列。如下图对于四个点都连通的图,我们假定从 a a a 点出发,可以将获得 ( 4 − 1 ) ! (4-1)! (41)! 条路径。(公式为 ( n − 1 ) ! (n-1)! (n1)!

在这里插入图片描述

2.2 代码

#include <iostream>
using namespace std;

//我们这里题目规模比较小 
int x[10]={0};         //城市编号数组,初值赋为0 
int bestx[10]={0};     //路线,初值赋为0 
int w = 0;             //过渡变量
int bestw = 1000;      //最优的费用

void Tsp(int a[10][10], int n, int s)
{
    if (s == n)
	{
        w = 0;//清零
        cout << "bestx: ";
        for (int i = 0; i < n; i++) {
            bestx[i] = x[i];
            cout << bestx[i] << " ";
            if (i < n - 1) {
                w += a[x[i]][x[i + 1]];
            }
            else {
                w += a[x[i]][x[0]];//回到起点的费用
            }
        }
        cout << "w:" << w << endl;
        if (bestw > w)
		{
            bestw = w;//更新最优值
        }
    }
    else
	{
        for (int i = s; i < n; i++)
		{
            //为什么要交换呢?因为要将x[s]作为起点进行往下搜索
            int t = x[i]; x[i] = x[s]; x[s] = t;
            Tsp(a, n, s + 1);
            t = x[i]; 
			x[i] = x[s]; 
			x[s] = t;
        }
    }
}

int main()
{
	cout<<"请输入城市的个数: "<<endl; 
    int n; //城市个数 
    cin>>n;
	 
	for (int i = 0; i < n; i++)
	{
        x[i] = i; //表示第i个城市编号,0到n-1
    }
	
	int a[10][10];  //a[i][j]表示从第i个城市到第j个的费用
	cout<<"请输入权值矩阵: "<<endl;
	for (int i = 0; i < n; i++) 
	{
        for (int j = 0; j < n; j++) 
		{
            cin >> a[i][j];
        }
    }
    
    Tsp(a, n, 1);//传1表示只搜从0开始的全排,传0表示所有全排
    cout << "最优的是:" << bestw << endl;
	return 0;
} 

在这里插入图片描述

三、回溯法解决

#include<iostream>
#include<algorithm>
#define MAX 10
using  namespace std;
int n;                   //城市个数
int a[MAX][MAX];         //城市间距离
int x[MAX];              //记录路径
int bestx[MAX]  = {0};   //记录最优路径
int bestp = 63355;       //最短路径长
int cp = 0;              //当前路径长
void backpack(int t){
     if(t>n)
	 {
        if((a[x[n]][1])&&(a[x[n]][1]+cp<bestp))
		{
              bestp = a[x[n]][1]+cp;
              for(int i = 1;i<=n;i++)
			  {
                 bestx[i] = x[i];
              }
        }
     }
	 else
	 {
         for(int i = t;i<=n;i++){
            //约束为当前节点到下一节点的长度不为0,限界为走过的长度+当前要走的长度之和小于最优长度
            if((a[x[t-1]][x[i]])&&(cp+a[x[t-1]][x[i]]<bestp)){
                swap(x[t],x[i]);   
                cp+=a[x[t-1]][x[t]];
                backpack(t+1);
                cp-=a[x[t-1]][x[t]];
                swap(x[t],x[i]);
            }
         }
    }
}
int main(){
    cout<<"请输入城市的个数:"<<endl;
    cin>>n;      //顶点数
    for(int i = 1;i<=n;i++){
         x[i] = i;  //表示第i个城市编号 
    }
    cout<<"请输入权值矩阵:"<<endl;
    for(int i = 1;i<=n;i++){
        for(int j = 1;j<=n;j++){
            cin>>a[i][j];
        }
    }
    backpack(2);
    cout<<"最少旅行费用为:"<<bestp<<endl;
    cout<<"旅行路径为:"<<endl;
    for(int i = 1;i<=n;i++){
       cout<<bestx[i]<<" ";
    }
    cout<<bestx[1];
    return 0;
}

在这里插入图片描述

四、分支界限法

4.1 介绍

 分支限界法就是先将根结点放入活结点表中,然后循环取出表头结点,如果满足约束条件和限界条件就可以将当前结点的子结点(或者说下一级结点)放入活结点表中,直至得到所求解或者是活结点表为空为止。根据活结点表的存储方式可以将分支限界法分为队列式分支限界法和优先队列式分支限界法。这两种方法使用到的数据结构来是队列和堆,如有需要可以自己写,当然用直接用C++标准模板库中的queue和priority_queue会方便很多。

4.2 代码

#include <bits/stdc++.h>
#include <string>
#include <vector>
using namespace std;
#define MAXN 10

int e[MAXN][MAXN];
int n, m, ans = 0x3f3f3f3f, vis[MAXN];
string anspath;

void bfs(){
    queue<pair<string, int> > q;
    int dis = 0;
    vector<int> path;
    q.push({"1", 0});
    while(!q.empty()){
        string path = q.front().first;
        int dis = q.front().second;
        int pos = path[path.length()-1] - '0';
        if( path.length() == n ){
            dis += e[pos][1];
            if(dis < ans)   ans = dis, anspath = path + char(1 + '0');
        }
        else{
            for(int i = 1; i <= n; i ++ ){
                if(find(path.begin(), path.end(), (i + '0')) != path.end())    continue;
                if(dis + e[pos][i] > ans)   continue;
                q.push({path + char(i + '0'), dis + e[pos][i]});
            }
        }
        q.pop();
    }
}

void show(){
    cout << ans << endl;
    for( int i = 0 ; i <= n ; i ++ )    cout << anspath[i] << (i == n ? "\n" : " ");
}

int main(){
    cin >> n >> m;
    for( int i = 0 ; i < m ; i ++ ){
        int u, v, w;
        cin >> u >> v >> w;
        e[u][v] = e[v][u] = w;
    }
    bfs();
    cout << ans << endl;
    for( int i = 0 ; i <= n ; i ++ )    cout << anspath[i] << (i == n ? "\n" : " ");
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

2018年计网408

第33题 下列 TCP/P应用层协议中, 可以使用传输层无连接服务的是()A. FTPB. DNSC. SMTPD. HTTP 本题考察TCP/IP体系结构中&#xff0c;应用层常用协议所使用的运输层服务。 如图所示。这是TCP/IP体系结构中常见应用层协议各自所使用的运输层端口,。在这些应用层协议中&#x…

Java Web 实战 20 - HTTP PK HTTPS ? HTTPS 大获全胜 ?

HTTP VS HTTPS 一 . HTTPS1.1 臭名昭著的运营商劫持1.2 加密是什么 ?1.3 HTTPS 的加密过程对称加密非对称加密引入 "证书" 机制 1.4 HTTP VS HTTPS Hello , 大家好 , 好久没有更新 JavaWeb 模块的内容了 . 博主这篇文章主要给大家讲解一下 HTTPS 以及与 HTTP 的区别…

吐血整理,金融银行测试的“火“到底在哪里?银行测试真正实施...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 银行里的软件测试…

许多网友可能还不知道,升级到Windows 11其实没那么复杂,只要符合几个条件可以了

如果你的Windows 10电脑可以升级Windows 11,现在怎么办?有几种方法可以免费安装新的操作系统。以下是你的选择。 如果你想升级到Windows 11,你可以随时购买一台已经安装了操作系统的新电脑。然而,如果你目前的Windows 10 PC满足所有必要的升级要求,那么在Windows 11免费的…

3.6-Dockerfile语法梳理及最佳实践

WORKDIR是设置当前docker的工作目录 ADD 和 COPY 为了将本地的一些文件添加到docker image里面&#xff0c;ADD 和 COPY的作用特别像&#xff0c;但是ADD 和 COPY还有一些区别&#xff0c;ADD不仅可以添加本地文件到docker里面&#xff0c;还可以将文件在添加到docker image里面…

AIRLOOK与商汤科技强强联合,打造“实景三维与AI大模型”结合的全新盛宴

实景三维中国建设作为数字中国建设的重要内容之一&#xff0c;是一项涉及多方面技术支撑的综合性工程&#xff0c;同时作为AI技术在其中发挥着至关重要的作用&#xff0c;AI大模型的发展也将进一步推动实景三维建模技术的创新和发展。在此背景下&#xff0c;AIRLOOK与商汤科技携…

七、文件包含漏洞

一、文件包含漏洞 解释&#xff1a;文件包含漏洞是一种注入型漏洞&#xff0c;其本质就是输入一段用户能够控制的脚本或者代码&#xff0c;并让服务端执行&#xff1b;其还能够使得服务器上的源代码被读取&#xff0c;在PHP里面我们把可重复使用的函数写入到单个文件中&#x…

Java Swing商品信息查询系统

内容要求 1&#xff09; 本次程序设计是专门针对 Java 课程的,要求使用 Java 语言进行具有一定代码量的程序开发。程序的设计要结合一定的算法&#xff0c;在进行代码编写前要能够设计好自己的算法。 2&#xff09;本次程序设计涉及到 Java 的基本语法&#xff0c;即课堂上所…

宠物信息服务预约小程序的效果如何

宠物的作用越来越重要&#xff0c;因此铲屎官们对自己爱宠的照顾也是加倍提升&#xff0c;而市场围绕宠物展开的细分服务近些年来逐渐增多&#xff0c;且市场规模快速增长。涉及之广&#xff0c;涵盖宠物衣食住行、医疗、美容、婚丧嫁娶等&#xff0c;各品牌争相抢夺客户及抢占…

Mysql之单行函数

Mysql之单行函数 单行函数数值类型函数字符串类型的函数日期和时间函数加密与解密函数信息函数 单行函数 函数的定义 函数在计算机语言的使用中贯穿始终&#xff0c;函数的作用是什么呢&#xff1f;它可以把我们经常使用的代码封装起来&#xff0c; 需要的时候直接调用即可。这…

【MySQL】insert和select单表查询详解(包含大量示例,看了必会)

insert和select 前言正式开始Create全列插入指定列插入多行插入插入失败就更新替换 Retrieveselect语法简介开始查询全列查询指定列查询select后面跟表达式对结果去重条件查询 查询的示例英语不及格的同学及英语成绩 ( < 60 )语文成绩在 [80, 90] 分的同学及语文成绩数学成绩…

《Fine-Grained Image Analysis with Deep Learning: A Survey》阅读笔记

论文标题 《Fine-Grained Image Analysis with Deep Learning: A Survey》 作者 魏秀参&#xff0c;南京理工大学 初读 摘要 与上篇综述相同&#xff1a; 细粒度图像分析&#xff08;FGIA&#xff09;的任务是分析从属类别的视觉对象。 细粒度性质引起的类间小变化和类内…

YOLOv8优化策略:轻量级Backbone改进 | 高效模型 (Efficient MOdel, EMO),现代倒残差移动模块设计 | ICCV2023

🚀🚀🚀本文改进:面向移动端的轻量化网络模型——EMO,它能够以相对较低的参数和 FLOPs 超越了基于 CNN/Transformer 的 SOTA 模型,支持四个版本EMO_1M, EMO_2M, EMO_5M, EMO_6M 🚀🚀🚀YOLOv8改进专栏:http://t.csdnimg.cn/hGhVK 学姐带你学习YOLOv8,从入门到…

JavaScript职责链模式

JavaScript职责链模式 1 什么是职责链模式2 举个例子3 用职责链模式重构代码4 灵活可拆分的职责链节点5 异步的职责链 1 什么是职责链模式 职责链模式是一种行为型设计模式&#xff0c;它允许将请求沿着处理者链进行传递&#xff0c;直到其中一个处理者能够处理该请求为止&…

C++算法入门练习——树的带权路径长度

现有一棵n个结点的树&#xff08;结点编号为从0到n-1&#xff0c;根结点为0号结点&#xff09;&#xff0c;每个结点有各自的权值w。 结点的路径长度是指&#xff0c;从根结点到该结点的边数&#xff1b;结点的带权路径长度是指&#xff0c;结点权值乘以结点的路径长度&#x…

RobotFramework框架之导入自己打包的python程序(十五)

引言 RobotFramework自动化框架&#xff08;以下简称RF&#xff09;之前文章我们讲了通过import第三方的library&#xff08;RequestsLibrary等&#xff09;&#xff0c;在实际项目中第三方的包并不能满足我们的需要&#xff0c;此时我们可自己编写python模块&#xff08;.py文…

springboot集成nacos并实现自动刷新

目录 1.说明 2.示例 3.自动刷新的注意点 1.说明 springboot项目中存在好多配置文件&#xff0c;比如配置数据信息&#xff0c;redis信息等等&#xff0c;配置文件可以直接放在代码&#xff0c;也可以放在像nacos这样的组件中&#xff0c;实现动态的管理&#xff0c;修改配置…

c++ list容器使用详解

list容器概念 list是一个双向链表容器&#xff0c;可高效地进行插入删除元素。 List 特点&#xff1a; list不可以随机存取元素&#xff0c;所以不支持at.(position)函数与[]操作符。可以对其迭代器执行&#xff0c;但是不能这样操作迭代器&#xff1a;it3使用时包含 #includ…

数据分析思维与模型:群组分析法

群组分析法&#xff0c;也称为群体分析法或集群分析法&#xff0c;是一种研究方法&#xff0c;用于分析和理解群体内的动态、行为模式、意见、决策过程等。这种方法在社会科学、心理学、市场研究、组织行为学等领域有广泛应用。它可以帮助研究人员或组织更好地理解特定群体的特…

算法通关村第十六关白银挑战——滑动窗口高频问题

关注微信公众号&#xff1a;怒码少年。回复关键词【电子书】&#xff0c;领取多本计算机相关电子书 公众号后台开启了咨询业务&#xff0c;欢迎大家向我提问&#xff0c;免费&#xff0c;为爱发电&#x1f60e; 大家好&#xff0c;我是怒码少年小码。 武汉今天真的超级冷&…