题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1421
题目分析可知:要获得最小的疲劳度,每次拿物品必然是拿重量最相近的两个物品,所以输入数据之后先排个序。
状态转移方程为:dp[i][j] = min(dp[i-1][j],dp[i-2][j-1]+weight),dp[i][j]表示前i个物品选出j对的最小疲劳度,dp初值赋为最大值,weight为第i个物品个前一个物品组队的疲劳度。
为了节约空间,可以用一个滚动数组来存储数据,
状态转移方程为:dp[cnt][j] = min(dp[(cnt+1)%2][j],dp[cnt][j-1]+weight);
#include <cstdio>
#include <cstring>
#include <string>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <iostream>
#include <algorithm>
using namespace std;
#define ll long long
#define int64 __int64
#define M 2005
int n , k , w[M] , dp[2][M];
int solve()
{
int i , j , cnt = 1;
memset(dp , 127 , sizeof dp);
dp[0][0] = dp[1][0]= 0;
for (i = 1 ; i < n ; i++)
{
int weight = (w[i]-w[i-1])*(w[i]-w[i-1]);
for (j = min(k,(i+1)/2) ; j > 0 ; j--)//前i+1个物品最多能选出(i+1)/2对
{
dp[cnt][j] = min(dp[(cnt+1)%2][j],dp[cnt][j-1]+weight);
}
cnt = (cnt+1)%2;
}
return dp[(cnt+1)%2][k];
}
int main()
{
while (~scanf("%d%d",&n,&k))
{
int i;
for (i = 0 ; i < n ; i++)scanf("%d",w+i);
sort(w,w+n);
printf("%d\n",solve());
}
return 0;
}