1. 程式人生 > >TSP問題之狀壓dp法

TSP問題之狀壓dp法

char 旅行商 因此 class for namespace state 一個 pac

首先,我們先來認識一下什麽叫做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法