hdu 1421 dp 入门题

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;
}


你可能感兴趣的:(hdu 1421 dp 入门题)