HDU 3127 WHUgirls(完全背包)

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

题意:

现在有一块X*Y的矩形布条, 然后有n种规格的x[i]*y[i]的小布条, 每种布条可以卖出val[i]的价值. 问你原始的X*Y布条最多能卖多少价值?   其中每次切割布条只能水平或垂直的切, 且一刀到底.

分析:

本题看起来比较麻烦, 但是搞懂原理后还是很简单的. 把当前还剩余的矩形布条看成容量, 那么我们就是再这有限的容量里面要找出最大价值的布条总和来.

令dp[i][j]==x 表示当前长i和宽j的布条能切割出的最大价值为x.

这里有个结论要注意: 我们每次从大矩形中切割出一个小矩形, 总是沿着大矩形的顶角边缘切割将不会丢失最优解.

比如一个i*j的大矩形, 我们如果要从中切割出一个x*y的小矩形, 有下面4种方式(大矩形可以选择先下垂直那刀或先下水平那刀,
小矩形能旋转):

(仔细体会上面这个图.)

有了上面的图, 下面我们的递推公式就出来了:

if(i>=r[k].x&& j>=r[k].y)

dp[i][j]=max(dp[i][j] , max( dp[i-r[k].x][j]+dp[r[k].x][j-r[k].y] ,dp[i-r[k].x][r[k].y]+dp[i][j-r[k].y] )+r[k].val );

if(i>=r[k].y && j>=r[k].x)

dp[i][j]=max(dp[i][j] , max( dp[r[k].y][j-r[k].x]+dp[i-r[k].y][j] ,dp[i-r[k].y][r[k].x]+dp[i][j-r[k].x] )+r[k].val );

上面两个公式好像看起来很复杂, 其实理解上面的图之后就很简单了.       本质就是:

原始矩形能获得的最大价值 == max(小矩形价值 + 被水平一刀和竖直一刀切割后剩下的两个矩形能获得的最大价值和 )

也就是求切割后的3个矩形的价值和, 看看哪种方式切割剩下的矩形价值和最大.(两刀之后,
原始矩形必然变成3个新矩形)

初始化: dp为全0.

最终所求: dp[X][Y].

注意:
完全背包问题限制条件的维度j和物品编号的维度i的循环先后顺序是可以互换的. 但是此题必须先循环X和Y的维度,
然后才是物品编号的维度.
因为一般的完全背包问题的最优解对于物品的选取顺序没有要求, 可以先区任何物品. 但是此题对于原始矩形来说, 你在它的顶角边缘先切割那个小矩形是明显不同的,有可能你先切割1号矩形就得不到最优解, 但是你先切割3号矩形才能得到最优解(仔细想想是不是).

AC代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1000+5;

int X,Y;//原始矩形宽和高
int n;  //有多少个小布条
struct Node//每个小布条
{
    int x,y;
    int val;
}r[10+5];

int dp[maxn][maxn];

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        //读取输入+初始化
        scanf("%d%d%d",&n,&X,&Y);
        for(int i=1;i<=n;i++)
            scanf("%d%d%d",&r[i].x,&r[i].y,&r[i].val);
        memset(dp,0,sizeof(dp));

        //递推,注意:先X和Y,然后才是矩形编号.
        //如果先循环矩形编号,就错了.
        for(int i=0;i<=X;i++)
        for(int j=0;j<=Y;j++)
        for(int k=1;k<=n;k++)
        {
            if(i>=r[k].x && j>=r[k].y)
                dp[i][j]=max( dp[i][j] , max( dp[i-r[k].x][j]+dp[r[k].x][j-r[k].y] , dp[i-r[k].x][r[k].y]+dp[i][j-r[k].y] )+r[k].val );
            if(i>=r[k].y && j>=r[k].x)
                dp[i][j]=max( dp[i][j] , max( dp[r[k].y][j-r[k].x]+dp[i-r[k].y][j] , dp[i-r[k].y][r[k].x]+dp[i][j-r[k].x] )+r[k].val );
        }

        //输出结果
        printf("%d\n",dp[X][Y]);
    }
}
时间: 2024-11-06 12:04:41

HDU 3127 WHUgirls(完全背包)的相关文章

hdu 3127 WHUgirls

题目: 链接:点击打开链接 题意: 武汉大学有很多漂亮的妹纸,,,,,,,他们有一块待剪的布,他们想把它剪成很多小块做围巾,每个人喜欢不同的风格,他们把每一块的价值写在了纸上,现在有一个机器,可以把一块布剪成两块矩形的布,要求你用这台机器把原始的大布剪成纸上出现的小布,他们希望的到小块布的价值最大,当然不要求用完所有的布.. 思路: 首先它是一个背包问题:1>大布尺寸是总容量,每个小布都有相应的费用,2>要求剪的小布的个数是不限的,3>每块小布都有价值,要求大布被裁剪后的最大价值,(完全

hdu 3127 WHUgirls(完全背包)

WHUgirls Time Limit: 3000/2000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 2251    Accepted Submission(s): 852 Problem Description There are many pretty girls in Wuhan University, and as we know, every girl lo

HDU 3127 WHUgirls【二维完全背包】

题意:给出一个长为a,宽为b的布,再给出n个围巾的规格(长x,宽y,价值c),问怎样裁剪能够得到最大的价值. ----第一次做的时候不会---然后放到今天做--发现还是不会---于是又--看题解了[email protected][email protected]=== 因为相同规格的围巾可以重复剪多次,且围巾的长和宽相当于两个约束,所以可以转换为二维费用的完全背包问题. 然后就是围巾的裁剪 第一种 横着减 裁切线分为两种对于左上的第一个图,当减去长为x,宽有长为y的一个矩形之后,剩余的面积之和

HDU 2955 Robberies --01背包变形

这题有些巧妙,看了别人的题解才知道做的. 因为按常规思路的话,背包容量为浮点数,,不好存储,且不能直接相加,所以换一种思路,将背包容量与价值互换,即令各银行总值为背包容量,逃跑概率(1-P)为价值,即转化为01背包问题. 此时dp[v]表示抢劫到v块钱成功逃跑的概率,概率相乘. 最后从大到小枚举v,找出概率大于逃跑概率的最大v值,即为最大抢劫的金额. 代码: #include <iostream> #include <cstdio> #include <cstring>

HDU 4501 多维背包

小明系列故事--买年货 Time Limit: 5000/2000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others) Total Submission(s): 2261 Accepted Submission(s): 1018 Problem Description 春节将至,小明要去超市购置年货,于是小明去了自己经常去的都尚超市. 刚到超市,小明就发现超市门口聚集一堆人.用白云女士的话说就是:"那家伙,那场面,真是人山人海,锣

HDU 2955 Robberies (01背包)

Robberies Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 11297    Accepted Submission(s): 4190 Problem Description The aspiring Roy the Robber has seen a lot of American movies, and knows that

HDU 1059 Dividing(多重背包)

HDU 1059 Dividing(多重背包) http://acm.hdu.edu.cn/showproblem.php?pid=1059 题意: 现在有价值为1,2,3,4,5,6的6种物品, 它们的数量为num[i]( 1<=i<=6 )个. 现在要问的是能否把所有的的物品分成两份且这两份物品的价值总和相同 ? 分析: 首先我们求出所有物品的价值和sum_val, 如果sum_val是奇数, 那么明显不能分. 那么sum_val为偶时, 我们令m=sum_val/2. 我能只要看看从所有

hdu 5389 dp类似背包

http://acm.hdu.edu.cn/showproblem.php?pid=5389 Problem Description Zero Escape, is a visual novel adventure video game directed by Kotaro Uchikoshi (you may hear about ever17?) and developed by Chunsoft. Stilwell is enjoying the first chapter of this

HDU 2844 Coins (组合背包)

题意   给你n种面额不同的金币和每种金币的个数  求这些金币能组合成的面额在m内有多少种 还是明显的背包问题  d[i]表示这些金币在i内能组合成的最大面额  初始化d为负无穷  d[0]=0  这样就可以保证d[i]恰好为i时才能为正值 原因可以自己想想  然后就用背包背吧  直接多重背包也可以过  但是分成多重背包和完全背包要快一点 #include<cstdio> #include<cstring> #include<algorithm> using names