3122 奶牛代理商 VIII
小徐是USACO中國區的奶牛代理商,專門出售質優價廉的“FJ"牌奶牛。
有一天,她的奶牛賣完了,她得去美國進貨。
她需要去N個奶牛農場詢問價格(小徐是個認真的人,買東西一定要貨比三家)。
給你一個鄰接矩陣,表示N個農場間的路徑長度,求小徐最少走多少路。(從農場1出發,最後回到出發點買)
N
鄰接矩陣
答案(見描述)
3
0 1 2
3 0 10
2 0 0
5
N<=15,路徑長度<=1000
TSP
分類標籤 Tags 點此展開
狀壓DP好惡心啊。。
這道題的關鍵點有兩個,
1.走過所有的點
2.最短路徑
第2個最短路徑比較好解決,n<=16的話,,一遍Floyd就可以
但是第一個條件,要走過所有的點。
我們可以考慮用狀態壓縮的方法來實現
我們可以用一個二進位制的字串表示這個點是否走過,比如說110表示已經走過了1和2這兩個點,第3個點還沒有經過
程式碼思路:
設定一個dp陣列,dp[now][j]表示在now狀態下,到達點j所需要的花費
首先我們需要暴力列舉i和j兩點,來求最短距離
其次,我們還需要列舉一個能夠包攬所有狀態的變數now,來記錄每一個能夠到達的狀態
當狀態now可以到達j的話,那麼說明我們可以通過這個狀態到達i(i和j之間必定有路徑)
最後列舉每個點,取一下最小值就可以
細節問題:
1.跑floyd的時候不要預先設定最大值,因為每兩個點(不相同)之間必定有邊相連
2.dp陣列的第一位必須要開的足夠大,最小是2^16,因為第一維記錄的是狀態而不是大小
3.now<=(1<<n)-1:
當n==3時,1<<3 == 2^3 == 8 == 1000
1000-1=111正好是三個點都到達的理想情況
4.now&(1<<(j-1))
j-1是為了不超邊界且列舉出所有情況
首先要明確,1<<(j-1)得到的一定是一個2^x的數,轉換成二進位制一定是1+000.....的形式
那麼當now&(1<<(j-1))有值時,就說狀態now是可以到達j點的
5.now|(1<<(i-1))
在進行這個運算的時候,now一定是滿足now&(1<<(j-1))!=0的(程式滿足順序執行)
那麼通過now狀態一定可以到達j點
而且1<<(i-1)也一定是一個2^x的數
所以now|(1<<(i-1))就是一個可以通過j到達i產生的新狀態
舉個栗子:
now=110010
i=100
那麼結果就是110110
程式碼:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 using namespace std; 6 const int MAXN=30; 7 int read(int & n) 8 { 9 char p='+';int x=0; 10 while(p<'0'||p>'9') 11 p=getchar(); 12 while(p>='0'&&p<='9') 13 x=x*10+p-48,p=getchar(); 14 n=x; 15 } 16 int dp[MAXN*2000][MAXN]; 17 int dis[MAXN][MAXN]; 18 int n; 19 void floyed() 20 { 21 for(int i=1;i<=n;i++) 22 for(int j=1;j<=n;j++) 23 for(int k=1;k<=n;k++) 24 if(i!=j&&j!=k&&i!=k) 25 dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]); 26 } 27 void zhuangya() 28 { 29 /*for(int i=1;i<=n;i++) 30 { 31 for(int j=1;j<=n;j++) 32 { 33 cout<<dis[i][j]<<" "; 34 } 35 cout<<endl; 36 }*/ 37 memset(dp,0xf,sizeof(dp)); 38 dp[1][1]=0; 39 for(int now=0;now<=(1<<n)-1;now++) 40 for(int i=1;i<=n;i++) 41 for(int j=1;j<=n;j++) 42 if((now&(1<<(j-1)))&&i!=j) 43 { 44 dp[now|(1<<(i-1))][i]= 45 min 46 ( 47 dp[now|(1<<(i-1))][i], 48 dp[now][j]+dis[j][i] 49 ); 50 } 51 int ans=0x7ffffff; 52 for(int i=2;i<=n;i++) 53 { 54 ans=min(ans,dp[(1<<n)-1][i]+dis[i][1]); 55 } 56 cout<<ans; 57 } 58 int main() 59 { 60 read(n); 61 for(int i=1;i<=n;i++) 62 for(int j=1;j<=n;j++) 63 read(dis[i][j]); 64 floyed(); 65 zhuangya(); 66 return 0; 67 }