UVA10271 佳佳的筷子 Chopsticks

假设筷子按长度排序为 $l_1,l_2,\cdots,l_n$,

可证明任意一组筷子 $(a, b, c) = (l_i,l_{i+1},l_k)$,即 $a, b$ 相邻。

那么 $f_{i, j}$ 表示在 $l_{i}$ 到 $l_n$ 中选出 $j$ 组筷子的最小花费,则

$$f_{i, j} = \begin{cases}0 ,&j = 0\\\infty,&3\times j>n - i + 1\\\min(f_{i + 1, j}, f_{i + 2,j - 1} + (l_{i + 1} - l_i) ^ 2),&\text{otherwise.}\end{cases}$$

解释一下第三种情况:

  1. 不选 $(l_{i}, l_{i + 1})$,$f_{i, j} = f_{i + 1, j}$

  2. 选,$f_{i, j} = f_{i + 2, j - 1} + (l_{i + 1} - l_i) ^ 2$

上代码:


#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int N = 5010;

int l[N];

int f[N][N];

int main() {
    int T; scanf ("%d", &T);
    while (T --) {
        int k, n; scanf ("%d%d", &k, &n);
        k += 8;
        for (int i = 1; i <= n; ++i) {
            scanf ("%d", &l[i]);
        }
        memset (f, 0x3f, sizeof (f));
        for (int i = n; i >= 1; --i) {
            f[i][0] = 0;
            for (int j = 1; j <= k; ++j) {
                if (3 * j > n - i + 1) break;
                f[i][j] = min (f[i + 1][j], f[i + 2][j - 1] + (l[i + 1] - l[i]) * (l[i + 1] - l[i]));
            }
        }
        printf ("%d\n", f[1][k]);
    }
    return 0;
}
posted @ 2022-04-18 12:23  wangzhongyuan  阅读(4)  评论(0编辑  收藏  举报  来源