题意:从n个筷子中挑选n+8个三根筷子的集合,假如三根筷子按从小到大是a,b,c,那么让8+k个总(a-b)^2的值最小。
题解:用一个f[i][j]数组表示前j个筷子组成i个集合的总最小(a-b)^2值,所以dp思想就是f[i][j] = min{f[i][j - 1], f[i - 1][j - 2] + (cho[j] - cho[j - 1])^2},也就是不选cho[j]时,f[i][j]的值就是f[i][j - 1],如果选cho[j]时,也要选cho[j - 1],因为这两者组合的(a-b)^2的值会最小,那么f[i][j]就是f[i - 1][j - 2] + (cho[j] - cho[j - 1])^2。注意要cho数组是降序,因为这样做保证了一个筷子一旦被选为一个集合中的筷子c就不会再次被放到其他集合里了。
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
const int N = 5005;
const int INF = 0x3f3f3f3f;
int t, k, n, cho[N];
int f[1005][N];
int main() {
scanf("%d", &t);
while (t--) {
scanf("%d%d", &k, &n);
for (int i = n; i >= 1; i--)
scanf("%d", &cho[i]);
k += 8;
for (int i = 0; i < 1005; i++)
for (int j = 0; j < N; j++)
f[i][j] = INF;
for (int i = 1; i <= n; i++)
f[0][i] = 0;
for (int i = 1; i <= k; i++) {
for (int j = i * 3; j <= n; j++)
f[i][j] = min(f[i][j - 1], f[i - 1][j - 2] + (cho[j] - cho[j - 1]) * (cho[j] - cho[j - 1]));
}
printf("%d\n", f[k][n]);
}
return 0;
}