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}$$
解释一下第三种情况:
-
不选 $(l_{i}, l_{i + 1})$,$f_{i, j} = f_{i + 1, j}$
-
选,$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;
}