描述

A 先生有很多双筷子。确切的说应该是很多根,因为筷子的长度不一,很难判断出哪两根是一双的。这天,A 先生家里来了K 个客人,A 先生留下他们吃晚饭。加上A 先生,A夫人和他们的孩子小A,共K+3个人。每人需要用一双筷子。A 先生只好清理了一下筷子,共N 根,长度为T1,T2,T3,……,TN。现在他想用这些筷子组合成K+3 双,使每双的筷子长度差的平方和最小。(怎么不是和最小??这要去问A 先生了,呵呵)

输入

共有两行,第一行为两个用空格隔开的整数,表示N,K(1≤N≤100,0<K<50),第二行共有N个用空格隔开的整数,为Ti每个整数为1~50之间的数。

输出

仅一行。如果凑不齐K+3双,输出-1,否则输出长度差平方和的最小值。

样例输入

10 1
1 1 2 3 3 3 4 6 10 20

样例输出

5

【思路】

首先应该想到是dp问题。先sort这样第i和第i-1根就是差距最小的了,

f[i][j]表示前i根组成j双筷子每双长度差的和的最小值。

在考虑第i根筷子时,需要做出的决策即使要不要把这只筷子加入到最优解中去,

若加入,则其与第(i-1)根筷子组成一对,f[i][j]=f[i-2][j-1]+(a[i]-a[i-1])*(a[i]-a[i-1]),否则f[i][j]=f[i-1][j] .

当然,上述决策过程依赖于以下先验知识:

当从小到大排好的 a,b,c,d 四根筷子组成两双时, ab,cd 这样的组合最优. 就是以上决策时采取的 将第i个筷子跟第i-1根组成一对.

故dp方程这样写

f[i][j]=min(f[i-1][j],f[i-2][j-1]+(a[i]-a[i-1])*(a[i]-a[i-1]));

【代码】

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<climits>
#include<cstring>
#include<algorithm>
using namespace std;
int  f[200][200],a[200];
int n,k,i,j;
int min(int a,int b)
{
    if(a<b)
        return a;
    else
        return b;
}
void init()
{
 scanf("%d%d",&n,&k);
 if((k+3)*2>n)cout<<-1<<endl,exit(0);
 for(i=1;i<=n;i++)
 scanf("%d",&a[i]);
 sort(&a[1],&a[n]+1);
}
int main()
{
  init();
  memset(f,0x3f,sizeof(f));
  for(i=0;i<=n;i++)f[i][0]=0;
  for(i=2;i<=n;i++)    
  for(j=1;j<=i/2;j++)
  f[i][j]=min(f[i-1][j],f[i-2][j-1]+(a[i]-a[i-1])*(a[i]-a[i-1]));
 
  printf("%d\n",f[n][k+3]);
  return 0;
}
05-11 17:30