WHUgirls
Time Limit: 3000/2000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 2286 Accepted Submission(s): 865
The first line of each case consists of three integers N, X, Y, N indicating there are N kinds of rectangular that you can cut in and made to scarves; X, Y indicating the dimension of the original cloth. The next N lines, each line consists of two integers, xi, yi, ci, indicating the dimension and the price of the ith rectangular piece cloth you can cut in.
Constrains
0 < T <= 20
0 <= N <= 10; 0 < X, Y <= 1000
0 < xi <= X; 0 < yi <= Y; 0 <= ci <= 1000
1 2 4 4 2 2 2 3 3 9
9
题意:
现在有一块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号矩形才能得到最优解。
#include<stdio.h>
#include<string.h>
int max(int x,int y)
{
return x>y?x:y;
}
int dp[1010][1010];
int x[15],y[15],value[15];
int main()
{
int t,n,X,Y;
int k,i,j;
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d",&n,&X,&Y);
for(i=0;i<n;i++)
scanf("%d%d%d",&x[i],&y[i],&value[i]);
memset(dp,0,sizeof(dp));
for(i=0;i<=X;i++)
{
for(j=0;j<=Y;j++)
{
for(k=0;k<n;k++)
{
if(i>=x[k]&&j>=y[k])
dp[i][j]=max(dp[i][j],max(dp[i-x[k]][y[k]]+dp[i][j-y[k]],dp[i-x[k]][j]+dp[x[k]][j-y[k]])+value[k]);
if(i>=y[k]&&j>=x[k])
dp[i][j]=max(dp[i][j],max(dp[i-y[k]][x[k]]+dp[i][j-x[k]],dp[y[k]][j-x[k]]+dp[i-y[k]][j])+value[k]);
}
}
}
printf("%d\n",dp[X][Y]);
}
return 0;
}