P1171 售货员的难题 - 状压DP【最短Hamilton路径】

P1171 售货员的难题

Sol:

最短Hamilton路径,经典的NPC问题,小数据可以通过状压DP 实现。
状态:\(f[i][j]\)表示当前在第i号点,且已经过的点的状态为j 时的最短Hamilton路径。
阶段:若以点为阶段,由于会从点i转移到点i+1,还可能从i+1转移到i-1,不具有无后效性,因此我们考虑以二进制状态为阶段进行转移。
决策:考虑由哪一个点转移而来。
转移:\(f[i][j]=\max \limits_{i\&(1<<i)\&\&i\&(1<<k)}(f[i][j],f[i\&(~(1<<k))][k]+dis[k][j])\)

注意:

1.判断好DP的状态,如果发现DP瞎转移or不转移时,多半是阶段找错了。

AC Code:

// luogu-judger-enable-o2
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<ctime>
using namespace std;
const int N = 20;
int d[N][N];
int f[1<<N][N];
int read(){
    int x=0,f=1;char ch=' ';
    while(ch>'9'||ch<'0') {if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    return x*f;
}
int main(){
//  freopen("data.in","r",stdin);
//  freopen("sol.out","w",stdout);
    double st=clock();
    int n;n=read();
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
            d[i][j]=read();
    memset(f,0x3f,sizeof(f));
    f[1][0]=0;
    for(int i=1;i<(1<<n);i++){
        for(int j=0;j<n;j++) if((i>>j)&1){      
            for(int k=0;k<n;k++) if((j!=k)&&((i>>k)&1)){
                if(f[i][j]>f[i^(1<<j)][k]+d[k][j]){
                    f[i][j]=f[i^(1<<j)][k]+d[k][j];
                }
            }
        }
    }
    int ans=(1<<30);
    for(int i=0;i<n;i++){
        ans=min(ans,f[(1<<n)-1][i]+d[i][0]);
    }
    printf("%d",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Loi-Brilliant/p/9757825.html