您的位置:首页 > 其它

HDU 1421 搬寝室

2013-07-29 19:34 169 查看

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
[k]);
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: