HDU 3127 WHUgirls(二维背包)

题目链接:【HDU 3127】

有一块X*Y的布,可以裁剪成n种不同的小碎步布,剪成xi*yi的碎布可以获得wi元,问将这块布剪成小碎布最多能获得多少钱?只能横着剪或者竖着剪,不能从中间抠出一块

二维dp,dp[j][k]表示j*k的布剪成小碎布最多能得到多少钱,j*k可以由三个小长方形组成:(这里有切割方式)

1、xi*yi、 j*(k-xi)、 (j-xi)*yi

2、xi*yi、 xi*(k-yi)、 (j-xi)*k

3、xi*yi、 j*(k-xi)、 (j-yi)*xi

4、xi*yi、 yi*(k-xi)、 (j-yi)*k

所以转移方程式是:

dp[j][k]  = max(dp[j][k], max(dp[j-xi][k]+dp[xi][k-yi], dp[j][k-yi]+dp[j-xi][yi])+wi);

dp[j][k]  = max(dp[j][k], max(dp[j-yi][k]+dp[yi][k-xi], dp[j][k-xi]+dp[j-yi][xi])+wi);

重点来了!

网上的绝大多数博客式直接用以下代码得到的dp[X][Y]作为最终的值输出,我觉得这并不是最终的正确答案,下面的代码过不了hdu -discuss里面的一个数据:

1
4 8 26
1 5 1
3 7 10
3 19 500
5 10 1000

这个答案应该是2521


for(int j=0; j<=X; j++)
{
	for(int k=0; k<=Y; k++)
	{
		for(int i=0; i<n; i++)
		{
			if(j>=x[i] && k>=y[i]) 
			{
				int ans = max(dp[j-x[i]][k]+dp[x[i]][k-y[i]], dp[j][k-y[i]]+dp[j-x[i]][y[i]]);
				dp[j][k] = max(dp[j][k], ans+w[i]);
			}	
			if(j>=y[i] && k>=x[i])
			{
				int ans = max(dp[j-y[i]][k]+dp[y[i]][k-x[i]], dp[j][k-x[i]]+dp[j-y[i]][x[i]]);
				dp[j][k] = max(dp[j][k], ans+w[i]);
			}	
		}
	}
}
布剪成小碎布之后还剩下一些没有价值的布,这有时会造成dp[X][Y]偏小(我觉得这也是为什么三个for位置换了之后,直接输出dp[X][Y]会wa的原因), 需要再加上代码中的两句话

下面这两个代码都是ac的

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <string>
using namespace std;
int dp[1010][1010];
int main()
{
	int t;
	scanf("%d", &t);
	while(t--)
	{
		memset(dp, 0, sizeof(dp));
		int n, X, Y, xi, yi, wi;
		scanf("%d%d%d", &n, &X, &Y);
		for(int i=0; i<n; i++)//这个循环放在最前面还是对的
		{
			scanf("%d%d%d", &xi, &yi, &wi);
			for(int j=0; j<=X; j++)
			{
				for(int k=0; k<=Y; k++)
				{
					if(j>=xi && k>=yi) 
					{
						int ans = max(dp[j-xi][k]+dp[xi][k-yi], dp[j][k-yi]+dp[j-xi][yi]);
						dp[j][k] = max(dp[j][k], ans+wi);
					}	
					if(j>=yi && k>=xi)
					{
						int ans = max(dp[j-yi][k]+dp[yi][k-xi], dp[j][k-xi]+dp[j-yi][xi]);
						dp[j][k] = max(dp[j][k], ans+wi);
					}	
				}
			}
		}
		int ans = dp[X][Y];//以下两句是我认为要加上去的
		for(int i=0; i<=X; i++) ans = max(ans, dp[i][Y]+dp[X-i][Y]);
		for(int i=0; i<=Y; i++) ans = max(ans, dp[X][i]+dp[X][Y-i]);
		printf("%d\n", ans);
	}
	return 0;
}

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <string>
using namespace std;
int dp[1010][1010];
int x[15], y[15], w[15];
int main()
{
	int t;
	scanf("%d", &t);
	while(t--)
	{
		memset(dp, 0, sizeof(dp));
		int n, X, Y;
		scanf("%d%d%d", &n, &X, &Y);
		for(int i=0; i<n; i++)
		{
			scanf("%d%d%d", &x[i], &y[i], &w[i]);
		}
		for(int j=0; j<=X; j++)
		{
			for(int k=0; k<=Y; k++)
			{
				for(int i=0; i<n; i++)
				{
					if(j>=x[i] && k>=y[i]) 
					{
						int ans = max(dp[j-x[i]][k]+dp[x[i]][k-y[i]], dp[j][k-y[i]]+dp[j-x[i]][y[i]]);
						dp[j][k] = max(dp[j][k], ans+w[i]);
					}	
					if(j>=y[i] && k>=x[i])
					{
						int ans = max(dp[j-y[i]][k]+dp[y[i]][k-x[i]], dp[j][k-x[i]]+dp[j-y[i]][x[i]]);
						dp[j][k] = max(dp[j][k], ans+w[i]);
					}	
				}
			}
		}
		int ans = dp[X][Y];
		for(int i=0; i<=X; i++) ans = max(ans, dp[i][Y]+dp[X-i][Y]);
		for(int i=0; i<=Y; i++) ans = max(ans, dp[X][i]+dp[X][Y-i]);
		printf("%d\n", ans);
	}
	return 0;
}



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值