吃奶酪

题目:

房间里放着 nn 块奶酪。一只小老鼠要把它们都吃掉,问至少要跑多少距离?老鼠一开始在 (0,0)点处。

 

4
1 1
1 -1
-1 1
-1 -1
答案是7.41

设dp[i][j]是状态为i处在第j个点的最小路径
那么对于一个确定的状态而言,我可以扫描它,把所有为1的点找出来
然后抠掉某一个1,得到的新状态就是i的上一个状态
我们可以枚举所有状态中的1,除了抠掉的那个
因为我们是要找一个点走到抠掉的那个点,使得路径最小。
#include <bits/stdc++.h>
using namespace std;
int n;
double x[17],y[17],dp[1<<15][16];
double ji(int q,int w){
    return sqrt((x[q]-x[w])*(x[q]-x[w])+(y[q]-y[w])*(y[q]-y[w]));
}
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)    cin>>x[i]>>y[i];
    for(int i=0;i<(1<<15);i++)
    for(int j=0;j<=15;j++)
    dp[i][j]=1e18;//double类型不能用memset 
    for(int i=1;i<(1<<n);i++)
    {
        for(int j=0;j<n;j++)
        {
            if(i&(1<<j))//这个位置有1 
            {
                if((1<<j)==i)
                {
                    dp[i][j]=ji(0,j+1);//刚从原点出发
                    continue;
                }
                else
                {
                    for(int k=0;k<n;k++)
                    {
                        if(k!=j&&((1<<k)&i))
                            dp[i][j]=min(dp[i][j],dp[i-(1<<j)][k]+ji(k+1,j+1));
                    }
                }
            }
        }
    }
    double inf=999999999;
    for(int i=0;i<=n-1;i++)    inf=min(inf,dp[(1<<n)-1][i]);
    printf("%.2lf",inf);
}

 19.3.17自己写的版本(下标从1起)

#include <bits/stdc++.h>
using namespace std;
int n;
double dp[1<<15][20];
double x[29],y[29],dis[20][20];
double d(int l,int r){
    return sqrt((x[l]-x[r])*(x[l]-x[r])+(y[l]-y[r])*(y[l]-y[r]));
}
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)    cin>>x[i]>>y[i];
    for(int i=0;i<(1<<n);i++)for(int j=0;j<=19;j++)    dp[i][j]=99999999;
    for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++)
    dis[i][j]=dis[j][i]=d(i,j);
    for(int i=1;i<=n;i++)
        dp[1<<(i-1)][i]=d(i,0);
    for(int i=1;i<(1<<n);i++)//枚举当前状态 
    {
        for(int j=1;j<=n;j++)//枚举出发点    
        {
            if(i&(1<<(j-1)))
            {
                for(int q=1;q<=n;q++)//枚举上一个状态的位置
                {
                    if(q==j)    continue;
                    if(i&(1<<(q-1)))
                    {
                        int k=i-(1<<(j-1));//上一行的状态
                        dp[i][j]=min(dp[i][j],dp[k][q]+dis[j][q]);    
                    }    
                } 
            }
        }
    }
    double ans=99999999;
    for(int i=1;i<=n;i++)
        ans=min(ans,dp[(1<<n)-1][i]);
    printf("%.2lf",ans);
}
View Code

 

posted @ 2020-03-12 15:05  倾叶子佮  阅读(177)  评论(0编辑  收藏  举报