大意:
在中国,众通常用一双筷子吃饭。但是L先生与众不同:他用三支筷子吃饭。其中的一支长筷子用来叉取大块的食物,而剩下两支用作普通筷子。两支普通筷子的长度应尽可能的接近,而长的那支只要是三支中最长的就可以了。对于一幅筷子的长度A,B,C(A≤B≤C),定义函数(A-B)2为这副筷子的“难用度”。
L先生邀请K个人参加他的生日聚会,并且想将他用筷子的方法介绍给其他人。他需要准备K+8副这样的筷子(给他自己、妻子、儿子、女儿、父亲、母亲、岳父、岳母以及K名客人)。但是L先生的筷子有很多不同的长度!给出所有筷子的长度,他需要找到一种组合K+8副筷子的方法,使得难用度的总和最小。
这道题我们先降序排序,然后再用动态规划去解决,为什么要降序排序呢?因为这三只筷子里有最长的一只,如果我们按已给的递增顺序递推,无法保证存在最长筷子,相反降序递推,因为这组数的最大值不可能成为一双筷子里的一只,只能是作为第三只筷子存在(或者不选)因此就避免了上面的问题。当然实现起来就不用排序了,因为题中已经给了递增顺序,倒过来就行了。
代码如下:
#include<stdio.h> #define MAXN 5000+10 #define MAXN1 1000+10 int a[MAXN], f[MAXN][MAXN1] = {0}; int T, n, k, i, j; void solve() { for(i = 1; i <= n; i ++) { for(j = 1; j*3 <= i && j <= k+8; j ++) { f[i][j] = f[i-2][j-1] + (a[i-1]-a[i])*(a[i-1]-a[i]); if(3*j < i && f[i][j] > f[i-1][j]) f[i][j] = f[i-1][j]; } } printf("%d\n",f[n][k+8]); } void input() { while(~scanf("%d", &T)) while(T --) { scanf("%d%d",&k, &n); for(int i = n; i; i --) scanf("%d",&a[i]); solve(); } } int main() { input(); return 0; }