TSP问题之状压dp法

Posted real_l

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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这个点的状态,那么就很好求解了对吧

POJ3311

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

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

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<string>
 5 #include<cstring>
 6 #define in(i) (i=read())
 7 using namespace std;
 8 const int inf=0x3f3f3f;
 9 int read()
10 {
11   int ans=0,f=1;
12   char i=getchar();
13   while(i<0||i>9)
14     {
15       if(i==-) f=-1;
16       i=getchar();
17     }
18   while(i>=0&&i<=9)
19     {
20       ans=(ans<<1)+(ans<<3)+i-0;
21       i=getchar();
22     }
23   return ans*f;
24 }
25 int n;
26 int dp[13][1<<13];
27 int mp[13][13];
28 void floyed()
29 {
30   for(int k=1;k<=n;k++)
31     for(int i=1;i<=n;i++)
32       for(int j=1;j<=n;j++)
33     mp[i][j]=min(mp[i][j],mp[i][k]+mp[k][j]);
34   return;
35 }
36 int main()
37 {
38   while(1)
39     {
40       int ans=inf;
41       in(n);
42       if(!n) break;
43       n++;
44       for(int i=1;i<=n;i++)
45     for(int j=1;j<=n;j++)
46       in(mp[i][j]);//输入每两个点之间的距离
47       floyed();//求出n+1个点两两之间的最短距离
48       memset(dp,inf,sizeof(dp));
49       dp[1][1]=0;//默认以1为起点,集合内最开始状态为1<<(1-1)=1,所以dp[1][1]=0
50       for(int i=1;i<(1<<n);i++)//枚举状态
51     {
52       for(int j=1;j<=n;j++)//枚举每个点
53         {
54           if((i&(1<<(j-1)))!=0)//判断这个是否在集合中
55         {
56           for(int k=1;k<=n;k++)//如果不在就以它为中转点转移
57             {
58               if(!(i&(1<<(k-1))))
59             {
60               dp[k][i|(1<<(k-1))]=min(dp[k][i|(1<<(k-1))],dp[j][i]+mp[j][k]);//状态转移方程
61             }
62             }
63         }
64         }
65     }
66       for(int i=2;i<=n;i++)
67     ans=min(ans,dp[i][(1<<n)-1]+mp[i][1]);//还要回来才是一个环,因此还要加上到起点的距离
68       cout<<ans<<endl;
69     }
70 }

 

以上是关于TSP问题之状压dp法的主要内容,如果未能解决你的问题,请参考以下文章

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

HDU 5418 Victor and World 状压DP的TSP问题

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

AcWing 91 最短Hamilton路径(状压dp)

hdu 3001 Travelling (三进制)状压dp

TSP变形(三进制状压)