洛谷 P1171 售货员的难题(状压dp)
传送门
解题思路
用一个数i的二进制表示某一位的村庄是否已经去过,dp[i][j]表示当前状态i,这一次去的村庄是j的最短路程。
然后就枚举i、j、k(k表示下一个去的村庄),然后在if判断是否符合条件后,用dp[i][j]更新dp[i|1<<(k-1)][k]。
注意边界的处理。
AC代码
1 #include<bits/stdc++.h> 2 using namespace std; 3 int n,m[25][25],dp[1048579][25],ans=0x3f3f3f3f; 4 int main(){ 5 memset(dp,0x3f,sizeof(dp)); 6 cin>>n; 7 for(int i=1;i<=n;i++){ 8 for(int j=1;j<=n;j++){ 9 cin>>m[i][j]; 10 } 11 } 12 dp[1][1]=0; 13 for(int i=1;i<=(1<<n)-1;i++){ 14 if(!(i&1)) continue; 15 for(int k=1;k<=n;k++){ 16 if(!(i&(1<<(k-1)))) continue; 17 for(int j=2;j<=n;j++){ 18 if(!(i&(1<<(j-1)))) { 19 dp[i|1<<(j-1)][j]=min(dp[i|1<<(j-1)][j],dp[i][k]+m[k][j]); 20 } 21 } 22 } 23 } 24 for(int i=1;i<=n;i++) ans=min(ans,dp[(1<<n)-1][i]+m[i][1]); 25 cout<<ans<<endl; 26 return 0; 27 }