3122 奶牛代理商 VIII

自為風月馬前卒發表於2017-06-15

3122 奶牛代理商 VIII

 

時間限制: 3 s
空間限制: 256000 KB
題目等級 : 大師 Master
 
 
 
題目描述 Description

小徐是USACO中國區的奶牛代理商,專門出售質優價廉的“FJ"牌奶牛。

有一天,她的奶牛賣完了,她得去美國進貨。

她需要去N個奶牛農場詢問價格(小徐是個認真的人,買東西一定要貨比三家)。

給你一個鄰接矩陣,表示N個農場間的路徑長度,求小徐最少走多少路。(從農場1出發,最後回到出發點買)

輸入描述 Input Description

N

鄰接矩陣

輸出描述 Output Description

答案(見描述)

樣例輸入 Sample Input

3

0 1 2

3 0 10

2 0 0

 

樣例輸出 Sample Output

5

資料範圍及提示 Data Size & Hint

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 }

 

相關文章