HDU 1421 搬寝室

http://acm.hdu.edu.cn/showproblem.php?pid=1421

动态规划题。

我们可以用一个二维dp来存储第有i个物品取拿j次所用的最少体力。首先进行从小到大的排序。则拿相邻的两个最省力。物品重量存在w数组中。

PS:以下数据里面的 i 代表有i个物品, j 代表这 i 个物品分 j 次拿。

因此我们可以增加一个物品 i ,拿取的次数还是不变,则分为两种情况:
1、新增的最后一个不拿,则体力消耗为i-1时拿j次的消耗dp[i-1][j]。   即状态方程为dp[i][j] = dp[i-1][j]
2、最后一个拿,则体力消耗为i-2(i - 1和 i 一起拿着最省力)时的消耗加上i - 1和 i 消耗的体力。    状态方程为dp[i][j] = dp[i-2][j] + (w[i] - w[i-1] * w[i] - w[i-1])
然后取里面小得值即为当前最小值。
综上两种情况,则状态方程为:dp[i][j] = min(dp[i -1][j] , dp[i-2][j] + (w[i] - w[i-1] * w[i] - w[i-1]))

还要注意
1、dp[2][1] = w[2] - w[1] * w[2] - w[1]
2、当取的次数 j*2 == n 的时候,只有一种取法,即dp[i][j] = dp[i-2][j] + (w[i] - w[i-1] * w[i] - w[i-1])   (1,2,3,4取2次,则肯定1和2是一次,2和3是一次)

还是不懂得话直接看代码是最好的。

AC代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>

#define MAXX 999999

using namespace std;

int dp[2010][2010];

bool cmp(int a, int b)
{
    return a<b;
}

int main()
{
    int n,k,i,j,mi;
    int w[2010];
    while(scanf("%d%d",&n,&k)!=EOF)
    {
        mi = MAXX;
        memset(dp,0,sizeof(dp));
        for(i = 1; i <= n; i++)
        {
            scanf("%d",&w[i]);
        }
        sort(w+1,w+n+1,cmp);
        dp[2][1] = (w[2]-w[1])*(w[2]-w[1]);
  //      printf("dp[2][1]:%d\n",dp[2][1]);
        for(i = 3; i <= n; i++)   //i个物品取j次
        {
            for(j = 1; j <= i/2; j++)  //第i个物品分j次拿
            {
                if(j*2==i)   //忘了这个判断了。
                {
                    dp[i][j]=dp[i-2][j-1]+(w[i]-w[i-1])*(w[i]-w[i-1]);
                }
                else
                {
                    dp[i][j] = min(dp[i-1][j]/*第i个不拿*/,dp[i-2][j-1]+(w[i]-w[i-1])*(w[i]-w[i-1])/*第i个拿*/);
                }
            }
        }
        printf("%d\n",dp[n][k]);
    }

    return 0;
}


 

posted on 2013-07-29 19:34  you Richer  阅读(135)  评论(0编辑  收藏  举报