值得注意的DP,可以证明:这个题目的最优解是2k个数按从大到小排序,一个数只有和相邻的数结合,才能使得差平方的和最小。因为n个数中取k对,一个数既可以和前一个数结合,又可以和后一个数结合,思维极其混乱。不知如何解。后参考网上解题报告得出:a[i]可以算成一个数与相邻的后一个数的差的平方,即,这样就转化为一维的。dp[n][k]定义为从n个数取k对的差平方的最小和,如果最后一个数是2k中的,则它必是跟它前一个数结合,dp[i][j]=dp[i-2][j-1]+a[i-1]; 如果最后一个数不属于2k中的,则dp[i][j]=dp[i-1][j]; 状态转移方程是:dp[i][j]=min(dp[i-2][j-1]+a[i-1],dp[i-1][j]);
AC代码:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int cmp(const void *a, const void *b){
return *(int *)a - *(int *)b;
}
int min(int x,int y){
return x>y?y:x;
}
int a[2005],dp[2005][1005];
int main()
{
int n,k,i,j;
while(scanf("%d%d",&n,&k)!=EOF){
for(i=1;i<=n;i++){
scanf("%d",&a[i]);
}
memset(dp,127,sizeof(dp));
qsort(a,n+1,sizeof(int),cmp);
for(i=1;i<=n;i++){
a[i]=(a[i] - a[i+1])*(a[i] - a[i+1]);
dp[i][0]=0;
}
dp[0][0]=0;
for(i=2;i<=n;i++){
for(j=1;2*j<=i;j++){
dp[i][j]=min(dp[i-2][j-1]+a[i-1],dp[i-1][j]);
}
}
printf("%d\n",dp[n][k]);
}
return 0;
}