问题简介

有n个城市,每个城市间均有道路,一个推销员要从某个城市出发,到其余的n-1个城市一次且仅且一次,然后回到再回到出发点。问销售员应如何经过这些城市是他所走的路线最短?

用图论的语言描述就是:给定一个权值为正数的赋权完全图,求各边权值和最小的哈密尔顿回路。

这个问题就是著名的旅行商问题(TSP,Traveling Salesman Problem),TSP问题是NP问题,没有已知的多项式时间的高效算法可以解决之一问题。问题在1930年首次被形式化,并且是在最优化中研究最深入的问题之一,许多优化方法都用它作为一个基准,例如动态规划,最邻近法,插入法,模拟退火算法,遗传算法,神经网络算法等。

经典应用实例

印制电路板转孔

在一块电路板上打成百上千个孔,转头在这些孔之间移动,要求移动的距离之和最小。把这个问题转化为TSP,孔相当于城市.孔到孔之问的移动时间就是距离,转头的移动距离之和就是一次巡回的距离

生产安排

假设要在同一组机器上制造n种不同的产品,生产是周期性进行的,即在每一个生产周期这n种产品都要被制造。要生产这些产品有两种开销,一种是制造第i种产品时所耗费的资金(1≤i≤n),称为生产成本,另一种是这些机器由制造第i种产品变到制造第j种产品时所耗费的开支cij称为转换成本。显然,生产成本与生产顺序无关。于是,我们希望找到一种制造这些产品的顺序,使得制造这n种产品的转换成本和为最小。由于生产是周期进行的,因此在开始下一周期生产时也要开支转换成本,它等于由最后一种产品变到制造第一种产品的转换成本。于是,可以把这个问题看成是一个具有n个结点,边成本为cij图的货郎担问题。

代码实现

给定一个n个顶点组成的带权有向图的距离矩阵d(i,j)(INF表示没有边)。要求从顶点0出发,经过每个顶点恰好一次后再回到顶点0.问所经过的边的总权重的最少值是多少?(2≤n≤15),(0≤d(i,j)≤1000).

分析:

虽然TSP是NP困难的,不过在程序设计竞赛中还是有可能出现这种范围较小的题目。

所有可能的路线共有(n-1)! 种,这是一个非常大的值,即使在本题n已经很小,仍无法试遍每一种情况。对于这个问题,我们可以用DP来解决。

假设现在已经访问过的顶点的集合(起点0当作还未访问过的顶点)为S,当前所在的顶点为v,用d[S][v]表示从顶点v出发访问剩余的所有顶点,最终回到顶点0的路径的权重之和最小的路径。

已经访问过的集合S如何表示?由于S是有基数最大为n的集合,所以可以用n为二进制来表示集合,把每一个元素的选取与否对应到一个二进制位中,从而状态压缩成一个整数,像这种针对集合的DP我们一般叫做状态压缩DP

时间复杂度O(2nn2)(2n * n种状态,每种状态有n种选择)。

代码:

 #include<stdio.h>
#include<cstring>
#include<algorithm>
using namespace std; const int INF = 0x3f3f3f3f;
const int maxn = ;
int n,m,G[maxn][maxn];
int d[ << maxn][maxn]; //记忆化搜索使用的数组 //已经访问过的节点集合为S,当前位置为v
//用d[S][v]从v出发访问剩余的所有顶点,最终回到顶点0的路径的权重总和的最小值
int dp(int S, int v)
{
int& ans = d[S][v];
if (ans >= ) return ans; //已经求出来了,直接返回
if (S == ( << n) - && v == ) return ans = ; //已经访问过所有节点并回到0号点
ans = INF;
for (int u = ; u < n; u++) if ((!((S >> u) & )) && G[v][u])
ans = min(ans, dp(S | ( << u), u) + G[v][u]);
return ans;
} void solve()
{
//memset(G, INF, sizeof(G));
memset(d, -, sizeof(d));
printf("%d\n", dp(, ));
}
int main()
{
int T;
scanf("%d", &T);
while (T--)
{
scanf("%d%d", &n,&m);
for (int i = ; i < m; i++)
{
int u, v,w;
scanf("%d%d%d", &u, &v,&w);
G[u][v] = w;
}
solve();
}
return ;
}

对于不是整数的情况,很多时候很难确定一个适合的递推顺序,因此使用记忆化搜索可以避免这个问题。不过在这个问题中,对于任意两个整数i,j,如果它们对应的集合满足S(i) ⊆ S(j),就有i ≤ j。所以这题还可以用循环求出答案。

 #include<stdio.h>
#include<cstring>
#include<algorithm>
using namespace std; const int INF = 0x3f3f3f3f;
const int maxn = ;
int n, m, G[maxn][maxn];
int d[ << maxn][maxn]; //记忆化搜索使用的数组 void solve()
{
//用足够大的值初始化数组
for (int S = ; S < ( << n); S++)
fill(d[S], d[S] + n, INF);
d[( << n) - ][] = ; //根据递推式依次计算
for (int S = ( << n) - ; S >= ; S--)
for (int v = ; v < n; v++)
for (int u = ; u < n; u++)
if ((!(S >> u & )) && G[v][u])
d[S][v] = min(d[S][v], d[S | << u][u] + G[v][u]);
printf("%d\n", d[][]);
}
int main()
{
int T;
scanf("%d", &T);
while (T--)
{
scanf("%d%d", &n, &m);
for (int i = ; i < m; i++)
{
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
G[u][v] = w;
}
solve();
}
return ;
}

参考链接:

https://baike.baidu.com/item/NP完全问题/4934286?fr=aladdin

https://baike.baidu.com/item/旅行商问题/7737042?fr=aladdin

https://baike.baidu.com/item/%E8%B4%A7%E9%83%8E%E6%8B%85%E9%97%AE%E9%A2%98

旅行商问题——状态压缩DP的更多相关文章

  1. TSP 旅行商问题(状态压缩dp)

    题意:有n个城市,有p条单向路径,连通n个城市,旅行商从0城市开始旅行,那么旅行完所有城市再次回到城市0至少需要旅行多长的路程. 思路:n较小的情况下可以使用状态压缩dp,设集合S代表还未经过的城市的 ...

  2. 最短路+状态压缩dp(旅行商问题)hdu-4568-Hunter

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4568 题目大意: 给一个矩阵 n*m (n m<=200),方格里如果是0~9表示通过它时要花 ...

  3. hoj2662 状态压缩dp

    Pieces Assignment My Tags   (Edit)   Source : zhouguyue   Time limit : 1 sec   Memory limit : 64 M S ...

  4. POJ 3254 Corn Fields(状态压缩DP)

    Corn Fields Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 4739   Accepted: 2506 Descr ...

  5. [知识点]状态压缩DP

    // 此博文为迁移而来,写于2015年7月15日,不代表本人现在的观点与看法.原始地址:http://blog.sina.com.cn/s/blog_6022c4720102w6jf.html 1.前 ...

  6. HDU-4529 郑厂长系列故事——N骑士问题 状态压缩DP

    题意:给定一个合法的八皇后棋盘,现在给定1-10个骑士,问这些骑士不能够相互攻击的拜访方式有多少种. 分析:一开始想着搜索写,发现该题和八皇后不同,八皇后每一行只能够摆放一个棋子,因此搜索收敛的很快, ...

  7. DP大作战—状态压缩dp

    题目描述 阿姆斯特朗回旋加速式阿姆斯特朗炮是一种非常厉害的武器,这种武器可以毁灭自身同行同列两个单位范围内的所有其他单位(其实就是十字型),听起来比红警里面的法国巨炮可是厉害多了.现在,零崎要在地图上 ...

  8. 状态压缩dp问题

    问题:Ignatius has just come back school from the 30th ACM/ICPC. Now he has a lot of homework to do. Ev ...

  9. BZOJ-1226 学校食堂Dining 状态压缩DP

    1226: [SDOI2009]学校食堂Dining Time Limit: 10 Sec Memory Limit: 259 MB Submit: 588 Solved: 360 [Submit][ ...

随机推荐

  1. Python-Django使用MemcachedCache缓存

    最近工作中使用到缓存,简单记录之... 关于django的几种缓存方式,就不在做介绍了,网上一搜一大把:1.8.2官方文档, Django 缓存,Python菜鸟之路:django缓存 学习了之后,选 ...

  2. 聊聊Java SPI机制

    一.Java SPI机制 SPI(Service Provider Interface)是JDK内置的服务发现机制,用在不同模块间通过接口调用服务,避免对具体服务服务接口具体实现类的耦合.比如JDBC ...

  3. JNI 接口规范

    1. 简介 Java 本地接口概述 背景 JDK 1.0 本地方法接口 Java 运行时接口 原始本地接口和 Java/COM 接口 目标 Java 本地接口方法 利用 JNI 编程 JDK 1.1. ...

  4. 13_android实现多线程下载_界面实现

    进度条这个东西可以给它创建一个布局.进度条叫ProgressBar. ProgressBar这个就是进度条. 默认的安卓进度条是一个圈圈,一圈一圈转. 之前咱们把一个XML文件转化成一个View对象, ...

  5. (二十七)分类信息的curd-分类信息修改

      修改分类步骤分析: 1.在list.jsp页面上点击修改(编辑) /store/adminCategory?method=getById&cid=??? 2.在getById方法中 获取c ...

  6. application、session、request、page的作用范围、Application,Session和Cookie的区别

    Web应用中的JSP和servlet都是由web服务器来调用,Jsp和Servlet之间通常不会相互调用,那么Jsp和Servlet之间交换数据就要用到application.session.requ ...

  7. linux软硬连接学习总结

    创建连接实质上就是给系统中已经存在的文件指定另外一个可以访问它的名称,linux系统当中连接的创建有两种形式:硬链接(Hard Link),与符号链接(Symbloic Link)既软链接. ln命令 ...

  8. <TLE>奇偶剪枝hdoj1010

    (奇偶剪枝)转自百度百科,讲的非常棒: http://baike.baidu.com/link?url=3g5bW7LszRVOVvFDFp6cL0ZZnAaOLUdpaNjc2leHoxkKU9Eh ...

  9. bzoj 2761: [JLOI2011]不重复数字【hash】

    map会T,双hash会冲突--于是非酋写了个三hash #include<iostream> #include<cstdio> #include<cstring> ...

  10. Gist使用经验

    注:本文只是分享Gist使用经验,不讨论类似软件或服务的优劣,对于技术或软件不要有傲慢与偏见 一.Gist是什么 关于Gist的详细介绍,请阅读官方文档About gists,下面只简略介绍我所用到的 ...