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

news2024/10/7 18:23:41

文章目录

  • 一、问题描述
  • 二、穷举法解决
    • 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" : " ");
}

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

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

相关文章

2023.11.19 hadoop之MapReduce

目录 1.简介 2.分布式计算框架-Map Reduce 3.mapreduce的步骤 4.MapReduce底层原理 map阶段 shuffle阶段 reduce阶段 1.简介 Mapreduce是一个分布式运算程序的编程框架&#xff0c;是用户开发“基于hadoop的数据分析应用”的核心框架&#xff1b; Mapreduce核心功能是…

图解系列--认证

单向散列函数 1.什么是单向散列函数 单向散列函数有一个输入和一个输出&#xff0c;其中输入称为消息&#xff0c;输出称为散列值。单向散列函数可以根据消息的内容计算出散列值&#xff0c;而散列值就可以被用来检查消息的完整性。 在指定的散列函数处理下&#xff0c;无论输…

Hive语法,函数--学习笔记

1&#xff0c;排序处理 1.1cluster by排序 &#xff0c;在Hive中使用order by排序时是全表扫描&#xff0c;且仅使用一个Reduce完成。 在海量数据待排序查询处理时&#xff0c;可以采用【先分桶再排序】的策略提升效率。此时&#xff0c; 就可以使用cluster by语法。 cluster…

支持4KHz回报还能无线充电,简约不简单的雷柏VT3S游戏鼠标上手

这两年国产鼠标的表现很让人惊喜&#xff0c;不仅外观做工越来越精细&#xff0c;配置也越来越强大&#xff0c;当然价格依然亲民。现在很容易找到一款搭载高端传感器、响应速度快、电池续航时间长&#xff0c;并且还支持无线充电的全能型鼠标。 我之前用雷柏的鼠标比较多&…

Java 教育局民办教育信息服务与监管平台

1) 项目背景 按照《中华人民共和国民办教育促进法》和《中华人民共和国政府信息公开条例》的相关规定&#xff0c;为满足学生和家长、社会各界获取权威信息的需求&#xff0c;着力解决服务老百姓最后一公里问题&#xff0c;达到宣传民办教育和引导家长择校的效果&#xff0…

Java Swing商品信息查询系统

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

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

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

Linux进程——system函数、popen函数

system函数&#xff08;执行shell 命令&#xff09; 头文件 #include <stdlib.h> 函数定义 int system(const char * string); 函数说明 system()会调用fork()产生子进程&#xff0c;由子进程来调用/bin/sh-c string来执行参数string字符串所代表的命令&#xff0c;…

4.Pod详解【四】

文章目录 4. Pod详解4.1 Pod介绍4.1.1 Pod结构4.1.2 Pod定义 4.2 Pod配置4.2.1 基本配置4.2.2 镜像拉取4.2.3 启动命令4.2.4 环境变量4.2.5 端口设置4.2.6 资源配额 4.3 Pod生命周期4.3.1 创建和终止4.3.2 初始化容器4.3.3 钩子函数4.3.4 容器探测4.3.5 重启策略 4.4 Pod调度4.…

牛客网刷题笔记三 寻找第K大+两数之和+合并两个排序的链表+用两个栈实现队列

算法题牛客网NC88 寻找第K大 题目&#xff1a; 思路就是做个排序&#xff0c;要求时间复杂度 O ( n log ⁡ n ) O(n\log n) O(nlogn)&#xff0c;因此选用快排。代码&#xff1a; class Solution:def quickSort(self, a, start, end):if start > end:returnval a[start]…

利用SD存储介质扩展MAXQ20000的非易失性数据存储空间

SD存储卡是一种可移动存储介质&#xff0c;通常用于相机、手机、平板电脑等设备中存储照片、视频、音乐等数据。SD存储卡的全称为Secure Digital Memory Card&#xff0c;是由SD Card Association制定的一种标准格式。它具有体积小、存储容量大、读写速度快、价格低廉等优点。目…

Triage沙箱监控

Triage沙箱可以免费分析恶意软件样本。最先进的恶意软件分析沙箱&#xff0c;具有您需要的所有功能。 在可定制的环境中提交大量样本&#xff0c;并对许多恶意软件系列进行检测和配置提取。立即查看公开报告并对您的恶意软件进行分类&#xff01; 官方网址&#xff1a;https:…

关于链表的几道算法题

1.删除链表的倒数第n个节点 力扣https://leetcode.cn/submissions/detail/482739445/ /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}* ListNode(int val) { this.val val; }* ListNode(…

Spring Boot中实现支付宝、微信和银联支付的功能

Spring Boot中实现支付宝、微信和银联支付的功能 在Spring Boot中实现支付宝、微信和银联支付的功能&#xff0c;通常需要使用它们各自的SDK&#xff08;Software Development Kit&#xff09;。以下是一个简单的示例代码&#xff0c;演示了如何在Spring Boot项目中集成支付宝…

22. 深度学习 - 自动求导

Hi&#xff0c;你好。我是茶桁。 咱们接着上节课内容继续讲&#xff0c;我们上节课已经了解了拓朴排序的原理&#xff0c;并且简单的模拟实现了。我们这节课就来开始将其中的内容变成具体的计算过程。 linear, sigmoid和loss这三个函数的值具体该如何计算呢&#xff1f; 我们…

使用Spring Boot结合JustAuth实现支付宝、微信、微博扫码登录功能

使用Spring Boot结合JustAuth实现支付宝、微信、微博扫码登录功能 在使用Spring Boot结合JustAuth实现支付宝、微信、微博扫码登录功能之前&#xff0c;需要先确保已经配置好Spring Boot项目&#xff0c;并且添加了JustAuth的依赖。你可以在项目的pom.xml文件中添加如下依赖&a…

麦克风阵列入门

文章引注&#xff1a; http://t.csdnimg.cn/QP7uC 一、麦克风阵列的定义 所谓麦克风阵列其实就是一个声音采集的系统&#xff0c;该系统使用多个麦克风采集来自于不同空间方向的声音。麦克风按照指定要求排列后&#xff0c;加上相应的算法&#xff08;排列算法&#xff09;就可…

2 Redis的高级数据结构

1、Bitmaps 首先&#xff0c;最经典的应用场景就是用户日活的统计&#xff0c;比如说签到等。 字段串&#xff1a;“dbydc”&#xff0c;根据对应的ASCII表&#xff0c;最后可以得到对应的二进制&#xff0c;如图所示 一个字符占8位&#xff08;bit&#xff09;&#xff0c;…

【GCN】GCN学习笔记一

谱域图卷积 卷积 卷积定义离散空间的卷积 图卷积简介 卷积定理谱域图卷积实现思路如何定义图上的傅里叶变换拉普拉斯矩阵 &#xff08;Laplacian Matrix&#xff09;拉普拉斯矩阵的性质拉普拉斯矩阵的谱分解拉普拉斯矩阵与拉普拉斯算子 图傅里叶变换 图上的信号表示经典傅里叶变…