poj 3311 Hie with the Pie

题意:

一个人要送pizza到一些地方,一个地方可以进过两次,这样经过中转的时间可能会更短。

问送完pizza会到原点的最少时间。

思路:

状压dp + Floyd?

经典的tsp问题,不过并没有想到用Floyd求最短距离。

我的做法是,更新一个状态时,更新两次,第一次更新最新的点,第二次更新经过中转点的最短距离,跟Floyd还是有相同之处的。

转移方程:

dp[S|(1<<k)][k] = min(dp[S|(1<<k)][k],dp[S][j]),j属于S集合。

代码:

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <algorithm>
 4 using namespace std;
 5 const int N = 12;
 6 const int inf  = 0x3f3f3f3f;
 7 int dp[(1<<N)][N];
 8 int mp[N][N];
 9 int main()
10 {
11     int n;
12     while (scanf("%d",&n)!=EOF&&n)
13     {
14         n++;
15         for (int i = 0;i < n;i++)
16         {
17             for (int j = 0;j < n;j++) scanf("%d",&mp[i][j]);
18         }
19         memset(dp,inf,sizeof(dp));
20         dp[1][0] = 0;
21         for (int i = 0;i < (1<<n);i++)
22         {
23             for (int j = 0;j < n;j++)
24             {
25                 if (!i&(1<<j)) continue;
26                 if (dp[i][j] >= inf) continue;
27                 for (int k = 0;k < n;k++)
28                 {
29                     dp[i|(1<<k)][k] = min(dp[i|(1<<k)][k],dp[i][j]+mp[j][k]);
30                 }
31             }
32             for (int j = 0;j < n;j++)
33             {
34                 if (!i&(1<<j)) continue;
35                 if (dp[i][j] >= inf) continue;
36                 for (int k = 0;k < n;k++)
37                 {
38                     dp[i|(1<<k)][k] = min(dp[i|(1<<k)][k],dp[i][j]+mp[j][k]);
39                 }
40             }
41         }
42         printf("%d
",dp[(1<<n)-1][0]);
43     }
44     return 0;
45 }
原文地址:https://www.cnblogs.com/kickit/p/8859837.html