返回顶部

洛谷 P1433 吃奶酪 (状压dp)

  • 题意:RT,老鼠可以在任意两点移动.

  • 分析:由于\(n\)的范围非常小,我们考虑状压,我刚开始是用一维dp转移的,但是这样的话会出现一个问题,也就是我们从上一个状态转移过来时,会出现不同坐标但状态值相同的情况,那么我们用一维就不能确定哪个坐标是最优的,所以要用二维dp来进行转移.\(dp[i][j]\)表示状态为\(j\),并且当前在第\(i\)个坐标的最短距离.那么转移的话,就从上一个状态的每一个点转移过来.

  • 代码:

    #include <bits/stdc++.h>
    #define ll long long
    #define fi first
    #define se second
    #define pb push_back
    #define me memset
    #define min(a,b) (((a)<(b))?(a):(b)) 
    #define rep(a,b,c) for(int a=b;a<=c;++a)
    #define per(a,b,c) for(int a=b;a>=c;--a)
    const int N = 1e6 + 10;
    const int mod = 1e9 + 7;
    const int INF = 0x3f3f3f3f;
    using namespace std;
    typedef pair<int,int> PII;
    typedef pair<ll,ll> PLL;
    ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
    ll lcm(ll a,ll b) {return a/gcd(a,b)*b;}
    
    int n;
    double x[20],y[20];
    double dp[20][35000];
    
    double get_dis(double x1,double y1,double x2,double y2){
        return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
    }
    
    int main(){
        ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
        cin>>n;
        rep(i,0,n-1) cin>>x[i]>>y[i];
        me(dp,127,sizeof(dp));
    
        rep(i,1,(1<<n)-1){
            rep(j,0,n-1){
                if((i&(1<<j))==0) continue;
                if(i==(1<<j)){
                    dp[j][i]=0;
                    continue;
                }
                rep(k,0,n-1){
                    if(j==k) continue;
                    if((i&(1<<k))==0) continue;
                    double dis=get_dis(x[j],y[j],x[k],y[k]);
                    dp[j][i]=min(dp[j][i],dp[k][i-(1<<j)]+dis);
                }
            }
        }
        double ans=1e18;
        rep(i,0,n-1){
            ans=min(ans,dp[i][(1<<n)-1]+get_dis(x[i],y[i],0.0,0.0));
        }
    
        cout<<fixed<<setprecision(2)<<ans<<'\n';
     
        return 0;
    }
    
posted @ 2021-04-26 13:25  _Kolibri  阅读(73)  评论(0)    收藏  举报