洛谷 P1336 吃奶酪

P1336 吃奶酪

题意

房间中放有n块奶酪。一只小老鼠(位于 \([0, 0]\) )要把它们都吃掉,问最少要跑多少距离。

输入

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

\(2\) 行到第 \((n \ + \ 1)\) 行,每行两个实数 \(x \ , \ y\) ,第 \((i \ + \ 1)\) 行表示第 \(i\) 块奶酪的位置 \([x, \ y]\)

输出

4
1 1
1 -1
-1 1
-1 -1
7.41

题目分析

状态压缩, \(f(i, \ s)\) 表示从i点开始,走完s集合中所有点的最短路径。最后再加上从初始点到 \(i\) 点的距离即可。

Code

#include <bits/stdc++.h>

using namespace std;

const int N = 16;

int n;
double x[N], y[N], dis[N][N];
double f[N][1 << N]; // f(i, s) 从i出发到达s集合所有点的最小距离

void get_dis ()
{
    for (int i = 0; i <= n; i ++ )
	for (int j = 0; j <= n; j ++ )
             dis[i][j] = sqrt((x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j]));
}

void solve ()
{
    cin >> n;
    for(int i = 1; i <= n; i ++ ) cin >> x[i] >> y[i];
    get_dis();
    for (int i = 0; i <= n; i ++ )
	for (int j = 0; j < (1 << n); j ++ )
	    f[i][j] = 1e18;
    // s 集合的所有状态
    for (int s = 0; s < (1 << n); s ++ )
        // 从i开始到达集合其他点
	for (int i = 1; i <= n; i ++ )
        {
            if ((s & (1 << i-1)) == 0) continue; // s中没有i
            if (s == (1 << i-1)) { f[i][s] = 0; continue; } // *** s 中只有一个i点
            for (int j = 1; j <= n; j ++ )
            {
                if ((s && (1 << j-1)) == 0) continue; // s 中没有j点
                // 转移状态,先从i到达j,然后从j到达其他点
                f[i][s] = min(f[i][s], f[j][s - (1 << i-1)] + dis[i][j]);
            }
        }
    double ans = -1;
    for (int i = 1; i <= n; i ++ )
    {
        double t = f[i][(1 << n) - 1] + dis[i][0]; // 从初始点到i点,再到达其他所有点
        if (ans == -1 || ans > t) ans = t;
    }
    cout.precision(2);
    cout << fixed << ans << endl;
}

signed main () 
{
    
        solve();

    return 0;
}
posted @ 2021-09-05 10:43  Horb7  阅读(31)  评论(0编辑  收藏  举报