动态规划经典问题--TSP问题

Travelling Salesman Problem

旅行商问题,即TSP问题(Travelling Salesman Problem)又译为旅行推销员问题、货郎担问题,是数学领域中著名问题之一。假设有一个旅行商人要拜访n个城市,他必须选择所要走的路径,路径的限制是每个城市只能拜访一次,而且最后要回到原来出发的城市。路径的选择目标是要求得的路径路程为所有路径之中的最小值。

旅行商问题是图论中最著名的问题之一,即“已给一个n个点的完全图,每条边都有一个长度,求总长度最短的经过每个顶点正好一次的封闭回路”。该问题通常被认为是一个NP完全问题。时间复杂度为O(n!)。因此,通常n的值不是很大。



因此我们如何求其近似解(非多项式时间算法)呢?这里使用动态规划

  1. 假定我们从城市1出发,经过了一些地方,并到达了城市j。毋庸置疑,我们需要记录的信息有当前的城市j。同时我们还需要记录已经走过的城市的集合。同理,使用S记录未走过的城市的集合也可以的,且运算方便。
  2. 于是我们可以得出状态转移方程 go(S,init)=min{go(S?i,i)+dp[i][init]}?s∈S go(s,init)表示从init点开始,要经过s集合中的所有点的距离
  3. 因为是NP问题,所以时间复杂度通常比较大。使用dis[s][init]用来去重,初始化为-1,如果已经计算过init—>S(递归形式),则直接返回即可


例: Sicily1000. Traveling Salesman Problem

题目大意:有编号1到N的N个城市,问从1号城市出发,遍历完所有的城市并最后停留在N号城市的最短路径长度。N<=20

那么如何有效地储存当前还未走过的城市集合S呢?使用一个整形即可。每个整形可以表示32位,即32个城市,用1代表当前未去,0代表当前已经访问过的点。因N<=20,所以S<=1048576.

代码如下:*

#include<iostream>
#include<cmath>
#include<iomanip>
using namespace std;
int s;
int N;//点的个数
int init_point;
double x[20];
double y[20];
double dp[20][20];//两个城市的距离
double dis[1048577][20];//2^20=1048576 表示出发点到S集合是否已经访问过
double go(int s,int init)
{
    if(dis[s][init]!=-1) return dis[s][init];//去重
    if(s==(1<<(N-1))) return dp[N-1][init];//只有最后一个点返回
    double minlen=100000;
    for(int i=0;i<N-1;i++)//只能在1到n-2点中查找
    {
        if(s&(1<<i))//如果i点在s中且不为发出点
        {
            if(go(s&(~(1<<i)),i)+dp[i][init]<minlen)
                minlen=go(s&(~(1<<i)),i)+dp[i][init];
        }
    }
    return dis[s][init]=minlen;
}
int main()
{
    int T;
    cin>>T;
    while(T--)//测试样例数
    {
        cin>>N;
        for(int i=0;i<N;i++)
            cin>>x[i]>>y[i];//读入城市的坐标
        for(int i=0;i<N;i++)
            for(int j=0;j<N;j++)
            {
                dp[i][j]=sqrt(pow((x[i]-x[j]),2)+pow((y[i]-y[j]),2));
                //计算两个城市的距离
            }   

        for(int i=0;i<pow(2,N);i++)
            for(int j=0;j<N;j++)
                dis[i][j]=-1;//去重数组初始化
        init_point=0;
        s=0;
        for(int i=1;i<N;i++)
            s=s|(1<<i);//从1开始,保证初始点没有在S里面
        double distance=go(s,init_point);
        cout<<fixed<<setprecision(2)<<distance<<endl;

    }
} 
时间: 2024-10-10 16:22:27

动态规划经典问题--TSP问题的相关文章

nyist oj 311 全然背包 (动态规划经典题)

全然背包 时间限制:3000 ms  |  内存限制:65535 KB 难度:4 描写叙述 直接说题意,全然背包定义有N种物品和一个容量为V的背包.每种物品都有无限件可用.第i种物品的体积是c,价值是w. 求解将哪些物品装入背包可使这些物品的体积总和不超过背包容量,且价值总和最大.本题要求是背包恰好装满背包时,求出最大价值总和是多少. 假设不能恰好装满背包,输出NO 输入 第一行: N 表示有多少组測试数据(N<7). 接下来每组測试数据的第一行有两个整数M.V. M表示物品种类的数目,V表示背

nyist oj 37 回文字符串 (动态规划经典)

回文字符串 时间限制:3000 ms  |  内存限制:65535 KB 难度:4 描述 所谓回文字符串,就是一个字符串,从左到右读和从右到左读是完全一样的,比如"aba".当然,我们给你的问题不会再简单到判断一个字符串是不是回文字符串.现在要求你,给你一个字符串,可在任意位置添加字符,最少再添加几个字符,可以使这个字符串成为回文字符串. 输入 第一行给出整数N(0<N<100) 接下来的N行,每行一个字符串,每个字符串长度不超过1000. 输出 每行输出所需添加的最少字符

nyist oj 214 单调递增子序列(二) (动态规划经典)

单调递增子序列(二) 时间限制:1000 ms  |  内存限制:65535 KB 难度:4 描述 给定一整型数列{a1,a2...,an}(0<n<=100000),找出单调递增最长子序列,并求出其长度. 如:1 9 10 5 11 2 13的最长单调递增子序列是1 9 10 11 13,长度为5. 输入 有多组测试数据(<=7) 每组测试数据的第一行是一个整数n表示序列中共有n个整数,随后的下一行里有n个整数,表示数列中的所有元素.每个整形数中间用空格间隔开(0<n<=1

nyist oj 311 完全背包 (动态规划经典题)

完全背包 时间限制:3000 ms  |  内存限制:65535 KB 难度:4 描述 直接说题意,完全背包定义有N种物品和一个容量为V的背包,每种物品都有无限件可用.第i种物品的体积是c,价值是w.求解将哪些物品装入背包可使这些物品的体积总和不超过背包容量,且价值总和最大.本题要求是背包恰好装满背包时,求出最大价值总和是多少.如果不能恰好装满背包,输出NO 输入 第一行: N 表示有多少组测试数据(N<7). 接下来每组测试数据的第一行有两个整数M,V. M表示物品种类的数目,V表示背包的总容

动态规划经典题目:最大连续子序列和

最大连续子序列和问题 给定k个整数的序列{N1,N2,...,Nk },其任意连续子序列可表示为{ Ni, Ni+1, ..., Nj },其中 1 <= i <= j <= k.最大连续子序列是所有连续子序中元素和最大的一个,例如给定序列{ -2, 11, -4, 13, -5, -2 },其最大连续子序列为{11,-4,13},最大连续子序列和即为20. 注:为方便起见,如果所有整数均为负数,则最大子序列和为0. 解决这样一个问题是一个很有趣的过程,我们可以尝试着从复杂度比较高的算法

nyist oj 17 单调递增最长子序列 (动态规划经典题)

单调递增最长子序列 时间限制:3000 ms  |  内存限制:65535 KB 难度:4 描述 求一个字符串的最长递增子序列的长度 如:dabdbf最长递增子序列就是abdf,长度为4 输入 第一行一个整数0<n<20,表示有n个字符串要处理 随后的n行,每行有一个字符串,该字符串的长度不会超过10000 输出 输出字符串的最长递增子序列的长度 样例输入 3 aaa ababc abklmncdefg 样例输出 1 3 7 来源 经典题目 动态规划的经典题目:好像还有好几种解法,我现在研究的

[leetcode]53Maximum Subarray动态规划经典题目:最大子串问题

/** * Find the contiguous subarray within an array (containing at least one number) * which has the largest sum. For example, given the array [-2,1,-3,4,-1,2,1,-5,4], the contiguous subarray [4,-1,2,1] has the largest sum = 6. click to show more prac

多线程动态规划算法求解TSP(Traveling Salesman Problem) 并附C语言实现例程

TSP问题描述: 旅行商问题,即TSP问题(Travelling Salesman Problem)又译为旅行推销员问题.货郎担问题,是数学领域中著名问题之一.假设有一个旅行商人要拜访n个城市,他必须选择所要走的路径,路径的限制是每个城市只能拜访一次,而且最后要回到原来出发的城市.路径的选择目标是要求得的路径路程为所有路径之中的最小值.这篇文章解决的tsp问题的输入描述是: TSP问题的动态规划解法: 引用一下这篇文章,觉得作者把动态规划算法讲的非常明白:https://blog.csdn.ne

动态规划经典问题03:数组中最大的数对差(或最小的数对差)

题目:在数组中,数字减去它右边的数字得到一个数对之差.求所有数对之差的最大值.例如在数组{2, 4, 1, 16, 7, 5, 11, 9}中,数对之差的最大值是11,是16减去5的结果. 参考:http://zhedahht.blog.163.com/blog/static/2541117420116135376632/ 讨论区:http://stackoverflow.com/questions/11858790/find-the-largest-possible-difference-in