http://acm.njupt.edu.cn/acmhome/problemdetail.do?&method=showdetail&id=1581
比赛描述
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,否则输出长度差平方和的最小值。
思考:1. 关键是找到递推公式,f(i, j) = min{ f(i-1, j), f(i-2, j-1) + (len[i]-len[i-1])^2 } 这个公式中i j都是增加的。
2.在计算过程中,初值很重要,这里应该是没有办法实现的时候,就是穷大。另外还要注意先计算什么,再
计算什么。
3 dp[N][K]={INT_MAX}这个实际上是给第一个赋值最大,其余的为o
4 还有使用memset是以字节为单位,初始化内存块。当初始化一个字节单位的数组时,可以用memset把每个数组单元初始化成任何你想要的值。如果是二维数组,赋值不成功。
memset函数的初始化只能对一维数组,对于每一行,是连续分配的; 然而对于各行之间,却不是连续非配的,容易出错
#include<cstdio>
#include<algorithm>
#include<ctime>
#include<iostream>
#include<cmath>
#include<string.h>
using namespace std;
#define N 105
#define K 60
int main() {
int dp[N][K];//注意,这样只给第一个赋值最大,其余为0
int a[N];
int k,n,kk,tn;
scanf("%d",&n);
scanf("%d",&k);
kk=k+3;
tn=0;
//memset(dp,10,sizeof(dp));
for (int i = 0; i <= n; i++)
for (int j = 0; j <= k + 3; j++)
dp[i][j] = 1000;
while(tn<n) {
scanf("%d",&a[tn++]);
}
if(n<2*kk) {
cout<<-1<<endl;
return 0;
}
sort(a,a+n);
dp[0][0]=0;
for(int i=2; i<=n; i++)
for(int j=1; j<=kk; j++) {
//f(i, j) = min{ f(i-1, j), f(i-2, j-1) + (len[i]-len[i-1])^2 }
int tt=dp[i-2][j-1]+(a[i-1]-a[i-2])*(a[i-1]-a[i-2]);
dp[i][j]=min(tt,dp[i-1][j]);
}
cout<<dp[n][kk]<<endl;
}