首先,我们先来认识一下什么叫做TSP问题

旅行商问题,即TSP问题(Traveling Salesman Problem)又译为旅行推销员问题、货郎担问题,是数学领域中著名问题之一。假设有一个旅行商人要拜访n个城市,他必须选择所要走的路径,路径的限制是每个城市只能拜访一次,而且最后要回到原来出发的城市。路径的选择目标是要求得的路径路程为所有路径之中的最小值。假设这个n很小,我们就可以使用状态压缩的方法求解,在一般的TSP问题中的用状压求解的题目,我们可以定义一个dp数组,dp[i][v],其中v表示一个集合,dp[i][v]表示到i这个点经过v中所有点的最小路径.

假设我们从s出发,最后再回到s

1.那么最开始,只有dp[s][{s}]=0,其余均等于inf

2.其他情况下,dp[i][state]=min(dp[i][state],dp[j][state']+c[j][i])

3.最后我们的结果,ans=min(ans,dp[i][state]+c[i][s]),因为我们要求的是一个环的最短路,所以还要加上回来的距离

那么还有一个问题,我们要如何存下这个集合,当然是用状态压缩的方法,s|1<<(k),表示由原来的状态s转移到加上k这个点的状态,那么就很好求解了对吧

POJ3311

题目大意:多组数据,给定n,一个起点0,以及这n+1个点之间的距离,求从起点出发经过每个点一次,再回到起点的最短距离.注意到n<=10,我们可以使用状压dp来做

思路:首先先预处理出这n+1个点之间的最短距离,因为n很小,我们可以使用floyed来处理.然后就是套我上面的说的三种情况,具体可以代码中的注解

#include<iostream>
#include<cstdio>
#include<cmath>
#include<string>
#include<cstring>
#define in(i) (i=read())
using namespace std;
const int inf=0x3f3f3f;
int read()
{
int ans=,f=;
char i=getchar();
while(i<''||i>''){if(i=='-') f=-; i=getchar();}
while(i>=''&&i<='') {ans=(ans<<)+(ans<<)+i-'';i=getchar();}
return ans*f;
}
int n;
int dp[][<<];
int mp[][];
void floyed()
{
for(int k=;k<=n;k++)
for(int i=;i<=n;i++)
for(int j=;j<=n;j++)
mp[i][j]=min(mp[i][j],mp[i][k]+mp[k][j]);
return;
}
int main()
{
while() {
int ans=inf; in(n);
if(!n) break;
n++;
for(int i=;i<=n;i++)
for(int j=;j<=n;j++)
in(mp[i][j]);//输入每两个点之间的距离
floyed();//求出n+1个点两两之间的最短距离
memset(dp,inf,sizeof(dp));
dp[][]=;//默认以1为起点,集合内最开始状态为1<<(1-1)=1,所以dp[1][1]=0
for(int i=;i<(<<n);i++)//枚举状态
for(int j=;j<=n;j++)//枚举每个点
if((i&(<<(j-)))!=)//判断这个是否在集合中
for(int k=;k<=n;k++)//如果不在就以它为中转点转移
if(!(i&(<<(k-))))
dp[k][i|(<<(k-))]=min(dp[k][i|(<<(k-))],dp[j][i]+mp[j][k]);//状态转移方程
for(int i=;i<=n;i++)
ans=min(ans,dp[i][(<<n)-]+mp[i][]);//还要回来才是一个环,因此还要加上到起点的距离
cout<<ans<<endl;
}
}

上述代码在洛谷应该是会T一个点的,因为重复使用位运算速度是会变慢的,所以我们可以提前处理出每个点左移多少位之后的数组,以及使用系统自带函数min也是很慢的\

#include<iostream>
#include<cstdio>
#include<cmath>
#include<string>
#include<cstring>
#define MIN(a,b) (a)<(b)?(a):(b)
#define in(i) (i=read())
using namespace std;
const int inf=0x3f3f3f;
int read()
{
int ans=,f=;
char i=getchar();
while(i<''||i>'') {if(i=='-') f=-; i=getchar();}
while(i>=''&&i<='') { ans=(ans<<)+(ans<<)+i-'';i=getchar();}
return ans*f;
}
int dp[<<][],mp[][],st[];
int n;
int main()
{
in(n);
int ans=inf;
for(int i=;i<=n;i++)
for(int j=;j<=n;j++)
in(mp[i][j]);
memset(dp,inf,sizeof(dp));
dp[][]=; st[]=;
for(int i=;i<=;i++) st[i]=st[i-]<<;//预处理
for(int i=;i<st[n];i++)
for(int j=;j<=n;j++)
if( dp[i][j]!=dp[][] && i&st[j-])
for(int k=;k<=n;k++)
if(!(i&st[k-]))
dp[i|st[k-]][k]=MIN(dp[i|st[k-]][k],dp[i][j]+mp[j][k]);
for(int i=;i<=n;i++)
ans=MIN(ans,dp[st[n]-][i]+mp[i][]);
printf("%d\n",ans);
return ;
}
												

TSP问题之状压dp法的更多相关文章

  1. HDU 5418 Victor and World (可重复走的TSP问题,状压dp)

    题意: 每个点都可以走多次的TSP问题:有n个点(n<=16),从点1出发,经过其他所有点至少1次,并回到原点1,使得路程最短. 思路: 给了很多重边,选最小的留下即可.任意点可能无法直接到达, ...

  2. POJ 3311 Hie with the Pie (状压DP)

    题意: 每个点都可以走多次的TSP问题:有n个点(n<=11),从点1出发,经过其他所有点至少1次,并回到原点1,使得路程最短是多少? 思路: 同HDU 5418 VICTOR AND WORL ...

  3. poj3311 TSP经典状压dp(Traveling Saleman Problem)

    题目链接:http://poj.org/problem?id=3311 题意:一个人到一些地方送披萨,要求找到一条路径能够遍历每一个城市后返回出发点,并且路径距离最短.最后输出最短距离即可.注意:每一 ...

  4. HDU 5067 Harry And Dig Machine(状压DP)(TSP问题)

    题目地址:pid=5067">HDU 5067 经典的TSP旅行商问题模型. 状压DP. 先分别预处理出来每两个石子堆的距离.然后将题目转化成10个城市每一个城市至少经过一次的最短时间 ...

  5. POJ3311 Hie with the Pie 【状压dp/TSP问题】

    题目链接:http://poj.org/problem?id=3311 Hie with the Pie Time Limit: 2000MS   Memory Limit: 65536K Total ...

  6. 状压DP 从TSP问题开始入门哦

      一开始学状压DP难以理解,后来从TSP开始,终于入门了nice!!!! 旅行商问题 :    给定n个城市和两两相互的距离 ,求一条路径经过所有城市,并且路径达到最下仅限于; 朴树想法: 做n个城 ...

  7. Hie with the Pie(POJ3311+floyd+状压dp+TSP问题dp解法)

    题目链接:http://poj.org/problem?id=3311 题目: 题意:n个城市,每两个城市间都存在距离,问你恰好经过所有城市一遍,最后回到起点(0)的最短距离. 思路:我们首先用flo ...

  8. DAG求最短路--TSP变形--状压dp

    DAG状压dp的一种 题目: $m$个城市,$n$张车票,第i张车票上的时间是$t_i$, 求从$a$到$b$的最短时间,如果无法到达则输出“impossible” 解法: 考虑状态:“现在在城市$v ...

  9. 状压DP小结

    看了一个多星期状压DP,总算有点明白,大概可以分为两种:数据是在矩阵中的,数据是线性的,在矩阵中的一般就是排兵布阵这一种的,还有一种线性结构中给定条件让你求最大权值,比如求最大权值路线,TSP问题等, ...

随机推荐

  1. CMDB介绍

    CMDB https://lupython.gitee.io/2018/05/05/CMDB%E4%BB%8B%E7%BB%8D/ 尚泽凯博客地址 传统运维与自动化运维的区别 传统运维: ​ 1.项目 ...

  2. C语言实例解析精粹学习笔记——35(报数游戏)

    实例35: 设由n个人站成一圈,分别被编号1,2,3,4,……,n.第一个人从1开始报数,每报数位m的人被从圈中推测,其后的人再次从1开始报数,重复上述过程,直至所有人都从圈中退出. 实例解析: 用链 ...

  3. Python3 logging模块&ConfigParser模块

    ''' 博客园 Infi_chu ''' ''' logging模块 该模块是关于日志相关操作的模块 ''' import logging # logging.debug('debug') # log ...

  4. [BZOJ1455]罗马游戏(左偏树)

    用并查集和左偏树维护士兵的关系 Code #include <cstdio> #include <algorithm> #define N 1000010 using name ...

  5. 【转】Ubuntu 14.04下Django+MySQL安装部署全过程

    一.简要步骤.(阿里云Ubuntu14.04) Python安装 Django Mysql的安装与配置 记录一下我的部署过程,也方便一些有需要的童鞋,大神勿喷~ 二.Python的安装 由于博主使用的 ...

  6. Spring+quartz cron表达式(cron手册官方)完美理解

    ------------------------------------- 15 17/1 14/3 * * ? 从每小时的17分15秒开始 每分钟的15秒执行一次14:17:15 ...14:59: ...

  7. 在Go语言里检测内存泄漏

    我们先来设定一下数据库,建立一个MySQL数据库表,名为users,里面有login_name.nickname.uid.password.forbidden几个字段,其中uid与forbidden为 ...

  8. 圣思源Java视频36节练习源码分享(自己的190+行代码对比老师的39行代码)

    题目: * 随机生成50个数字(整数),每个数字范围是[10,50],统计每个数字出现的次数 * 以及出现次数最多的数字与它的个数,最后将每个数字及其出现次数打印出来, * 如果某个数字出现次数为0, ...

  9. Anytime项目开发记录4

    做事情列表,我在程序中命名为“正在做”. 这是一个Fragment,应用的主页面,由一个MainActivity加上DoingListFragment和PersonFragment组成.PersonF ...

  10. Qt 实现脉搏检测-1-心跳曲线部分

    最新的想法就是写一个显示脉搏的东西,主要就是通过串口读取硬件(检测心跳的)传来的数据,在显示一下. 先实现画心跳曲线 如下图 先来电干货, 首先,在这个代码中,第一次用到了list这个东东 所以,关于 ...