题目描述
中国人吃饭必须要用筷子。C先生与常人不同,他的一副筷子有3只,一对再加上一根比较长的,用来穿比较大的食物。两只较短的筷子的长度应该尽可能接近,但是最长的那根的长度是无所谓的。如果一副筷子的长度分别是A,B,C(A<=B<=C),则用(A-B)2的值表示这副筷子的质量,显然这个值越小,质量越高。
C先生邀请了K个朋友去吃饭,而且他要为每个人准备一副这种特殊的筷子。C先生的家里有8个人,因此你总共必须准备K+8副筷子。不过C先生发现他的筷子有各种各样不同的长度,他必须找到一种办法搭配好K+8副筷子,使得这些筷子的质量值之和最小。
输入格式
第一行有一个整数T,表示文件中共有T组测试数据。T的值不超过20。每一组测试数据的第一行是两个整数K和N,(0<=K<=1000, 3K+24<=N<=5000)。K是邀请朋友的人数,N是C先生家里储备的筷子总根数。接下来的一行有N个正整数,表示这N根筷子的长度;这N个数是从小到大给出的,并且每一根筷子的长度值不超过32000。
输出
对于每一组输入数据,输出单独一行,表示最小的质量值之和。你的答案应当写到stick.out中。
样例输入
1
1 40
1 8 10 16 19 22 27 33 36 40 47 52 56 61 63 71 72 75 81 81 84 88 96 98 103 110 113 118 124 128 129 134 134 139 148 157 157 160 162 164
样例输出
23
结题思路:
动态规划问题,难点在于要选3只筷子,因为C筷子比A,B筷子都要大,由题意知筷子从小到大排列,所以应该想到倒着每三只筷子更新,f[i][j]表示从最后一只筷子到第i只筷子(包括)组成j组筷子的最优解,条件是((n-i)>=j*3)这样才能够用。动态转移方程为:
f[i][j]=min(f[i+2][j-1]+(a[i+1]-a[i])*(a[i+1]-a[i]),f[i+1][j]);当选i时,i+1,i+2也要选, i+2只筷子一定比i,i+1只筷子大,所以得出上式前半部分,当第i不选时,f[i][j]值与f[i+1][j]一样,得出后半部分,再注意初始化即可。
参考程序:
//
// main.cpp
// ylzx3031
//
// Created by 胡竣峰 on 14-8-23.
// Copyright (c) 2014年 胡竣峰. All rights reserved.
//
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=5005;
int a[N],f[N][N/5];
int main()
{
int t;
cin>>t;
while (t--){
memset(a,0,sizeof(a));
memset(f,0x7f,sizeof(f));
int n,k;
cin>>k>>n;
k+=8;
for (int i=1;i<=n;i++) cin>>a[i];
for (int i=1;i<=n;i++) f[i][0]=0;
for (int i=n;i>=1;i--)
for (int j=1;j<=k;j++)
if (n-i>=3*j)
f[i][j]=min(f[i+2][j-1]+(a[i+1]-a[i])*(a[i+1]-a[i]),f[i+1][j]);
cout<<f[1][k]<<endl;
}
}