洛谷P1433吃奶酪

吃奶酪

题目描述

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

输入格式

第一行有一个整数,表示奶酪的数量 \(n\)

\(2\) 到第 \((n + 1)\) 行,每行两个实数,第 \((i + 1)\) 行的实数分别表示第 \(i\) 块奶酪的横纵坐标 \(x_i, y_i\)

输出格式

输出一行一个实数,表示要跑的最少距离,保留 \(2\) 位小数。

样例 #1

样例输入 #1

4
1 1
1 -1
-1 1
-1 -1

样例输出 #1

7.41

提示

数据规模与约定

对于全部的测试点,保证 \(1\leq n\leq 15\)\(|x_i|, |y_i| \leq 200\),小数点后最多有 \(3\) 位数字。

提示

对于两个点 \((x_1,y_1)\)\((x_2, y_2)\),两点之间的距离公式为 \(\sqrt{(x_1-x_2)^2+(y_1-y_2)^2}\)


\(2022.7.13\):新增加一组 \(\text{Hack}\) 数据。


这是一道比较明显的状压dp

状态表示 f[i][j]:在第j个点,当前状态为i的所有路径,属性:最小值
状态计算:可以从前往后推,也可以从后往前考虑,从前往后考虑的话,枚举j这个点可能由哪些点转移过来f[i |(1<<(k - 1))][k] = min(f[i |(1<<(k - 1))][k], f[i][j] + a[j][k]);

#include <iostream>
#include <algorithm>
#include <cstring>
#include <math.h>

using namespace std;
const int N = 20, M = 1 << N;
double f[M][N], a[N][N];
struct point
{
    double x, y;
}p[N];

int main()
{
// freopen("1.in","r",stdin);
    int n;cin >> n;
    for(int i = 0; i < (1 << n); ++ i)
        for(int j = 0; j <= n; ++j)
            f[i][j] = 2e9;
    
    for(int i = 1; i <= n; ++i)
    {
        //x,y均为实数
        double x, y; cin >> x >> y;
        p[i] = {x, y};
    }
    //预处理出来每个点到每个点的距离
    for(int i = 0; i <= n; ++i)
        for(int j = 0; j <= n; ++ j)
            a[i][j] = sqrt((p[i].x - p[j].x) * (p[i].x - p[j].x) + (p[i].y - p[j].y) * (p[i].y - p[j].y));
    //因为第0个转移时不符合状态转移方程,这时我们单独跑一遍0到每个点的状态
    for(int i=1;i<=n;++i) f[1<<(i-1)][i]=a[0][I];
    //此时我们只用考虑正常的转移
    for(int i=0;i<(1<<n);++i)
    {
        for(int j=1;j<=n;++j)
            //只有当第j位为1时状态i才表示已经在第j个点了
            if(i&(1<<(j-1)))
            {
                for(int k=1;k<=n;++k)
                //只有当状态i的第k位为0也就是说还没有到达过,我们才用k去转移
                if(!(i&(1<<(k-1)))) f[i|(1<<(k-1))][k]=min(f[i|(1<<(k-1))][k],f[i][j]+a[j][k]);
            }
    }
    double res = 2e9;
    //找到符合状态的所有值中的最小值
    for(int i = 1; i <= n; ++ i)    res = min(res, f[(1<<n)-1][i]);
    printf("%.2lf",res);
    return 0;
}
posted @ 2022-10-27 23:02  cxy8  阅读(15)  评论(0编辑  收藏  举报