TSP问题之状压dp法
首先,我们先来认识一下什么叫做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这个点的状态,那么就很好求解了对吧
题目大意:多组数据,给定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法的更多相关文章
- HDU 5418 Victor and World (可重复走的TSP问题,状压dp)
题意: 每个点都可以走多次的TSP问题:有n个点(n<=16),从点1出发,经过其他所有点至少1次,并回到原点1,使得路程最短. 思路: 给了很多重边,选最小的留下即可.任意点可能无法直接到达, ...
- POJ 3311 Hie with the Pie (状压DP)
题意: 每个点都可以走多次的TSP问题:有n个点(n<=11),从点1出发,经过其他所有点至少1次,并回到原点1,使得路程最短是多少? 思路: 同HDU 5418 VICTOR AND WORL ...
- poj3311 TSP经典状压dp(Traveling Saleman Problem)
题目链接:http://poj.org/problem?id=3311 题意:一个人到一些地方送披萨,要求找到一条路径能够遍历每一个城市后返回出发点,并且路径距离最短.最后输出最短距离即可.注意:每一 ...
- HDU 5067 Harry And Dig Machine(状压DP)(TSP问题)
题目地址:pid=5067">HDU 5067 经典的TSP旅行商问题模型. 状压DP. 先分别预处理出来每两个石子堆的距离.然后将题目转化成10个城市每一个城市至少经过一次的最短时间 ...
- POJ3311 Hie with the Pie 【状压dp/TSP问题】
题目链接:http://poj.org/problem?id=3311 Hie with the Pie Time Limit: 2000MS Memory Limit: 65536K Total ...
- 状压DP 从TSP问题开始入门哦
一开始学状压DP难以理解,后来从TSP开始,终于入门了nice!!!! 旅行商问题 : 给定n个城市和两两相互的距离 ,求一条路径经过所有城市,并且路径达到最下仅限于; 朴树想法: 做n个城 ...
- Hie with the Pie(POJ3311+floyd+状压dp+TSP问题dp解法)
题目链接:http://poj.org/problem?id=3311 题目: 题意:n个城市,每两个城市间都存在距离,问你恰好经过所有城市一遍,最后回到起点(0)的最短距离. 思路:我们首先用flo ...
- DAG求最短路--TSP变形--状压dp
DAG状压dp的一种 题目: $m$个城市,$n$张车票,第i张车票上的时间是$t_i$, 求从$a$到$b$的最短时间,如果无法到达则输出“impossible” 解法: 考虑状态:“现在在城市$v ...
- 状压DP小结
看了一个多星期状压DP,总算有点明白,大概可以分为两种:数据是在矩阵中的,数据是线性的,在矩阵中的一般就是排兵布阵这一种的,还有一种线性结构中给定条件让你求最大权值,比如求最大权值路线,TSP问题等, ...
随机推荐
- python学习之控制流2
配置环境:python 3.6 python编辑器:pycharm 代码如下: #!/usr/bin/env python #-*- coding: utf-8 -*- # 控制流语句: # if语句 ...
- mysql根据二进制日志恢复数据/公司事故实战经验
根据二进制日志恢复 目的:恢复数据,根据二进制日志将数据恢复到今天任意时刻 增量恢复,回滚恢复 如果有备份好的数据,将备份好的数据导入新数据库时,会随着产生二进制日志 先准备一台初始化的数据库 mys ...
- elasticsearch搜索引擎搭建
在该路径下,运行elasticsearch.bat该命令,后面访问127.0.0.1:9200 出现如下界面说明启动成功 elasticsearch-head操作elasticsearch的图形界面, ...
- C语言Windows程序开发—CreateWindow函数介绍【第03天】
(一)CreateWindow函数的参数介绍: HWND CreateWindow( LPCTSTR lpClassName, //Windows窗口中预定义的控件结构体,包括:BUTTON(按钮), ...
- Linux编程之Epoll高并发
网络上所有资料都说epoll是高并发.单线程.IO重叠服用的首选架构,比select和poll性能都要好,特别是在有大量不活跃连接的情况下.具体原理就不阐述了,下面说说使用. 具有有三个函数: #in ...
- 8 TFTP代码详解 协议写在程序中
1.版本1:发送请求 # -*- coding:utf-8 -*- import struct from socket import * #0. 获取要下载的文件名字: downloadFileNam ...
- ORB-SLAM 代码笔记(五)Frame类
Frame类的成员变量主要包含从摄像头获取的图像的 1. 特征点信息(关键点+描述字) 2. 尺寸不变特征所用金字塔信息,这些都定义在ORBextractor对象中 3. 词袋模型参数,用于跟踪失败情 ...
- mac 安装php redis扩展
git clone git://github.com/nicolasff/phpredis.git cd ./phpredis phpize 如果报 Cannot find autoconf. Ple ...
- 关于相对布局RelativeLayout的各种属性介绍
RelativeLayout相对布局是个人觉得在android布局中比较常用且好用的一个,当然如果想让布局更漂亮是需要多种布局混合搭建的,这里就需要更深入的学习了,在这只介绍下有关相对布局的东西. 相 ...
- 给socks-proxy-agent增加认证
由于需要使用socks代理,查看了nodejs的各种socks库,最终的结论是socks库是其中最完善的,而socks-proxy-agent是以其为基础的封装,可以直接和http模块对接. 不过在尝 ...