zoukankan      html  css  js  c++  java
  • 洛谷1433吃奶酪(状压dp)

      给出n个点(n<=15),从(0,0)出发,问最短走多远,才能经过所有的点,可以在任何位置结束。

      今天有学弟来问的一个题,之前做的时候还没学状压,写了个爆搜+剪枝,数据太水$O(n!)$给水过去了,今天再看发现算是个状压dp的入门题吧,之前的代码提交发现数据加强TLE了,就又补了一下。

      对经过的点状态进行状压,状态表示为i,位运算上每位为0表示未经过,为1则表示经过,采用dp[i][j]表示i状态下,若当前在j点的最短距离,对于已经经过的点k,那么可以从k走到j点,就有$dp[i][j]=dp[i-(1<<j)][k]+dis(j,k)$,转移方程也就出来了,$dp[i][j]=min(dp[i][j],dp[i-(1<<j)][k]+dis(k,j)$,其中满足$ (1<<k)&i $不为0,转移也就很方便了,最后对满状态下的(1<<n)-1,枚举最后一项取最小的即可,时间复杂度$O(n*2^{n})$。

      最后附上代码

    #include<bits/stdc++.h>
    
    using namespace std;
    typedef long long ll;
    typedef long double ld;
    typedef unsigned long long ull;
    typedef pair <double,double> pdd;
    #define rep(i,x,y) for(int i=x;i<y;i++)
    #define rept(i,x,y) for(int i=x;i<=y;i++)
    #define per(i,x,y) for(int i=x;i>=y;i--)
    #define all(x) x.begin(),x.end()
    #define pb push_back
    #define fi first
    #define se second
    #define mes(a,b) memset(a,b,sizeof a)
    #define mp make_pair
    #define dd(x) cout<<#x<<"="<<x<<" "
    #define de(x) cout<<#x<<"="<<x<<"
    "
    #define debug() cout<<"I love Miyamizu Mitsuha forever.
    "
    const double inf=1e18;
    pdd point[20];
    double dp[35000][20];
    
    double dis(const pdd &s1,const pdd &s2)
    {
        return sqrt( (s1.fi-s2.fi)*(s1.fi-s2.fi)+(s1.se-s2.se)*(s1.se-s2.se) );
    }
    int main()
    {
        ios::sync_with_stdio(false);
        cin.tie(0);
        int n;
        cin>>n;
        rep(i,0,n) cin>>point[i].fi>>point[i].se;
        rep(i,1,1<<n)
        {
            rep(j,0,n)
            {
                dp[i][j]=inf;
                if((1<<j)&i)
                {
                    if((1<<j)==i)
                    {
                        dp[i][j]=dis(mp(0,0),point[j]);
                        continue;
                    }
                    else
                    {
                        rep(k,0,n)
                            if(k!=j&&((1<<k)&i))
                                dp[i][j]=min(dp[i][j],dp[i-(1<<j)][k]+dis(point[k],point[j]));
                    }
                }
            }
        }
        double ans=inf;
        rep(i,0,n)
            ans=min(ans,dp[(1<<n)-1][i]);
        cout<<fixed<<setprecision(2)<<ans<<"
    ";
        return 0;
    }
  • 相关阅读:
    使用fscanf读取文本文件
    实验室开发机系统结构图
    字符串是否为数字及有效性检查
    winXP系统通过蓝牙在笔记本和手机之间传递数据
    HarborGIS3D场景编辑器速成街区数据
    判断一个浮点数是否为NAN(INF)
    单文档中只是想得到当前View类的指针
    windows控制台中使用不同颜色显示不同类型的日志
    c++中enum 如何使用
    陈佩斯
  • 原文地址:https://www.cnblogs.com/FZUzyz/p/12323511.html
Copyright © 2011-2022 走看看