http://acm.hdu.edu.cn/showproblem.php?pid=1421
中文题
思路:首先要找出怎么将所有的物品组合成一对一对的,题目要求疲劳之最小,也就是一对之中两个物品的重量的差距最小。那么就需要运用排序了,将物品从小到大排序,从遍历物品直到倒数第二个,将每一个物品和下一个物品组合成一对,这样就会发现如果我们先选了这一对,那么下一对就不可以选了,因为两者中有一个元素是重复的。
大概理清思路之后发现状态定义不出来。。。不知道怎么样才保证他是k对。。。dp果然得慢慢来,慢慢培养自己的感觉吧。
定义状态:dp[i][j]表示从i件物品中选取出j对来
分成两种情况,一种是不选当前对dp[i][j] = dp[i-1][j],一种是选当前对 dp[i][j] = dp[i-2][j-1]+a[i-1]
状态转移方程:dp[i][j] = min(dp[i-1][j],dp[i-2][j-1]+a[i-1])
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define M 2009
#define INF 0x3f3f3f3f
int a[M];
int dp[M][M]; // dp[i][j]表示从i件物品中选取出j对来
int main()
{
int n,k;
while(scanf("%d %d",&n,&k)==2)
{
for(int i = 1;i <= n;i++)
scanf("%d",&a[i]);
sort(a+1,a+n+1);//从小到大排使得差距最小
for(int i = 1;i <= n-1;i++)
a[i] = (a[i]-a[i+1])*(a[i]-a[i+1]); //计算出每一对的疲劳度
for(int i = 1;i <= n;i++)
for(int j = 0;j <= n;j++)
{
dp[i][j] = INF; //由于是找出最小值所以赋初值为INF
}
for(int i = 1;i <= n;i++)
{
dp[i][0] = 0; //从i件中选取0对的话疲劳值肯定为0
for(int j = 0;2*j <= i;j++)
{
if(i==1) dp[i][j] = dp[i-1][j]; //特殊情况
else dp[i][j] = min(dp[i-1][j],dp[i-2][j-1]+a[i-1]);
}
}
printf("%d\n",dp[n][k]);
}
return 0;
}