码迷,mamicode.com
首页 > 其他好文 > 详细

HDU 3127 WHUgirls(完全背包)

时间:2014-10-27 19:32:22      阅读:173      评论:0      收藏:0      [点我收藏+]

标签:acm   algorithm   dp   算法   

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种方式(大矩形可以选择先下垂直那刀先下水平那刀, 小矩形能旋转):

bubuko.com,布布扣

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

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

       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的循环先后顺序是可以互换的. 但是此题必须先循环XY的维度, 然后才是物品编号的维度. 因为一般的完全背包问题的最优解对于物品的选取顺序没有要求, 可以先区任何物品. 但是此题对于原始矩形来说, 你在它的顶角边缘先切割那个小矩形是明显不同的,有可能你先切割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]);
    }
}

HDU 3127 WHUgirls(完全背包)

标签:acm   algorithm   dp   算法   

原文地址:http://blog.csdn.net/u013480600/article/details/40512311

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!