Travelling HDU - 3001

原题链接

考察:状压dp

这道题的扩展题 91. 最短Hamilton路径

思路:

       首先要处理这几点:

  1. 可以以任意点为出发点,也就是说初始化f[i点为1,其余点为0的状态][i] = 0.
  2. 预处理10位以内的3进制数.

      设定f[i][j]为最后的落脚点为i,此时的状态为j.集合划分为倒数第二个点为k.f[i][j] = f[k][j-{i}] +w[k][j](只限于k、j存在路径)

      更新答案需要j的每一位都>=1.

时间复杂度:60000*10*10

注意:外层循环必须是路径,内层是各个点.因为状态必须按照拓扑序列更新.也就是我们必须先更新小的.再解释一点,先枚举状态可以让该状态是当前最优解,计算后面的状态也是用此最优解.

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <algorithm>
 4 #include <cstring>
 5 using namespace std;
 6 typedef long long ll;
 7 const int N = 11,Max = 59048,INF = 0x3f3f3f3f;
 8 int w[N][N],m,n,nums[Max+10][N];
 9 int bits[N] = {1,3,9,27,81,243,729,2187,6561,19683,59049};
10 ll f[N][Max+10];
11 void inits()//预处理3进制数 
12 {
13     for(int i=0;i<Max;i++)
14     {
15         int t = i;
16         for(int j=0;j<10;j++)
17             nums[i][j] = t%3,t/=3;
18     }
19 }
20 int main()
21 {
22     inits();
23     while(scanf("%d%d",&n,&m)!=EOF)
24     {
25         ll ans = INF;
26         memset(w,0x3f,sizeof w); memset(f,0x3f,sizeof f);
27         for(int i=0;i<N;i++) f[i][bits[i]] = 0;
28         for(int i=1;i<=m;i++)
29         {
30             int a,b,c; scanf("%d%d%d",&a,&b,&c);
31             w[b-1][a-1] = w[a-1][b-1] = min(w[a-1][b-1],c);
32         }//DP状态需要按拓扑序计算 
33         for(int i=0;i<bits[n];i++)
34         {
35             bool ok = 1;
36             for(int j=0;j<n;j++)
37             {
38                 if(!nums[i][j]) ok = 0;
39                 for(int k=0;k<n;k++)
40                 {
41                     if(!nums[i][k]||w[k][j]>=INF||k==j) continue;
42                     f[j][i] = min(f[k][i-bits[j]]+w[k][j],f[j][i]);
43                 }
44             }
45             if(!ok) continue;
46             for(int t=0;t<n;t++) ans = min(ans,f[t][i]);
47         }
48         if(ans==INF) printf("-1\n");
49         else printf("%lld\n",ans);
50     }
51     return 0;
52 }

 

posted @ 2021-02-13 16:20  acmloser  阅读(47)  评论(0编辑  收藏  举报