洛谷 P1433 吃奶酪 状压DP

题目描述


分析

比较简单的状压DP
我们设(f[i][j])为当前的状态为(i)且当前所在的位置为(j)时走过的最小距离
因为老鼠的坐标为((0,0)),所以我们要预处理出(f[1<<(i-1)][i] (1 leq i leq n))的值
同时在读入的时候顺便处理处任意两个奶酪之间的距离
下面是状态转移方程

    for(int i=1;i<(1<<n);i++){
        for(int j=1;j<=n;j++){
            if((i&(1<<(j-1)))==0) continue;
            for(int k=1;k<=n;k++){
                if(k==j) continue;
                if((i&(1<<(k-1)))==0) continue;
                f[i][j]=min(f[i][j],f[i^(1<<(j-1))][k]+jl[k][j]);
            }
        }
    }

思路就是枚举当前状态已经到达的城市,在已经到达的城市中枚举当前所在的城市
同时枚举上一个状态所在的城市,在所有状态中取一个最小值即可

代码

#include<bits/stdc++.h>
using namespace std;
typedef double dd;
const int maxn=18;
dd f[1<<maxn][maxn];
dd jlx[maxn],jly[maxn];
dd jl[maxn][maxn];
int main(){
    for(int i=1;i<(1<<18);i++){
        for(int j=0;j<18;j++){
            f[i][j]=10000000.0;
        }
    }
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%lf%lf",&jlx[i],&jly[i]);
        f[1<<(i-1)][i]=(dd)sqrt(jlx[i]*jlx[i]+jly[i]*jly[i]);
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            jl[i][j]=(dd)sqrt((jlx[i]-jlx[j])*(jlx[i]-jlx[j])+(jly[i]-jly[j])*(jly[i]-jly[j]));
        }
    }
    for(int i=1;i<(1<<n);i++){
        for(int j=1;j<=n;j++){
            if((i&(1<<(j-1)))==0) continue;
            for(int k=1;k<=n;k++){
                if(k==j) continue;
                if((i&(1<<(k-1)))==0) continue;
                f[i][j]=min(f[i][j],f[i^(1<<(j-1))][k]+jl[k][j]);
            }
        }
    }
    dd ans=100000000.0;
    for(int i=1;i<=n;i++){
        ans=min(ans,f[(1<<n)-1][i]);
    }
    printf("%.2lf
",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/liuchanglc/p/13198757.html