Travelling HDU - 3001
考察:状压dp
这道题的扩展题 91. 最短Hamilton路径
思路:
首先要处理这几点:
- 可以以任意点为出发点,也就是说初始化f[i点为1,其余点为0的状态][i] = 0.
- 预处理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 }