CF1437C 大厨莫诺卡普

1 CF1437C 大厨莫诺卡普

2 题目概要:

大厨莫诺卡普刚刚把 \(𝑛\) 个盘子放进烤箱里。 他知道\(𝑖\)菜的最佳烹饪时间为 \(𝑡_𝑖\) 分钟。

在任何正整数分钟 \(𝑇\) 莫诺卡普不能从烤箱中取出超过一个盘子。如果第 \(𝑖\) 道菜是在某一分钟的 \(𝑇\) 上放出来的,那么它的不愉快值就是 \(|𝑇−𝑡_𝑖|\),也就是 \(𝑇\)\(𝑡_𝑖\) 之间差的绝对值。一旦盘子出了烤箱,它就不能再被放进去了。

莫诺卡普应该把所有的盘子都从烤箱里拿出来。莫诺卡普能获得的最小的总不愉快值是多少?

3 解题思路

分析性质,我们发现:取盘子一定是按照他们 \(t\) 的递增顺序来取的。这是因为,如果我们先取了 \(t\) 更大的盘子,那么该盘子产生的代价将比后取该盘子的代价要大。于是我们可以将给出的 \(t\) 递增排序。

由于我们要求出的值是最小代价,物体的维度是由时间构成的,我们便可以考虑如下状态。

\(dp[i][j]\) 表示在取了前 \(i\) 个盘子,第 \(i\) 个盘子取出时间为 \(j\) 的情况下的最小代价。

对于这个状态,我们发现它是由取 \(i-1\) 个盘子,第 \(i-1\) 个盘子取出时间为 \(1\)~\(j\) 的状态的最小值加上 \(\vert t_i - j\rvert\) 更新来的。转移方程便得出了:

\[dp[i][j] = min(dp[i][j], dp[i-1][k] + \lvert t_i - j \rvert)(k \in[1,j]) \]

注意:由于我们可以在大于 \(n\) 的时刻取出盘子,因此 \(j\) 可以最大可以取到 \(2*n\)

4 代码实现

代码(空格警告):

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 205;
int n, maxn, T;
int a[N], dp[N][2*N];
int main()
{
    cin >> T;
    while (T--)
    {
        maxn = 0x3f3f3f3f;
        memset(dp, 0x3f, sizeof(dp));
        cin >> n;
        for (int i = 1; i <= n; i++) cin >> a[i];
        sort(a+1, a+n+1);
        for (int i = 1; i <= 2*n; i++) dp[0][i] = 0;
        for (int i = 1; i <= n; i++)
        {
            for (int j = i; j <= 2*n; j++)
            {
                if (j == 1) dp[i][j] = abs(1 - a[1]);
                for (int k = 1; k < j; k++)
                {
                    dp[i][j] = min(dp[i][j], dp[i-1][k] + abs(a[i] - j));
                }
            }
        }
        for (int i = 1; i <= 2*n; i++)
        {
            maxn = min(maxn, dp[n][i]);
        }
        cout << maxn << endl;
    }    
    return 0;
}

欢迎关注我的公众号:智子笔记

posted @ 2021-02-05 15:33  David24  阅读(50)  评论(0编辑  收藏  举报