最近一直都在学DP,说实话,这要学的还真多,还不好理解,苦逼的人……
题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=232
这题是一道完全揹包的题目,看完题目后,感觉没有思路,就算是有也是O(n^3)的复杂度,蛋疼中……后来第二天就想到以前做到一道题……差不多,就是没有那个高度,求最长的矩形嵌套,so……AC了。
大体思路如下:因为有n种规格的方块,叠起来要使得放上去的方块的长和宽都要严格小于下面的方块,而每一种都是无限使用,但显然每一种规格的最多会用到2个,因为叠上去的面要比下面的严格小,顶多能放两个(其中有一个可以转到其它面),再放同一种规格的就不符合要求了。所以把三维的转化一下,定个规则,每一种规格都会形成三个不同的长,宽(x和y,x和z,y和z)的方块,那么就总共有3*n个方块,给它们排个序,从面大的到面小的(规定那一面必须是各自的x,y)。转移方程就是:
f[ i ] = max( f[ j ] ) + z[ i ]; ( 0<= j < i ; z[ i ] 是第i个方块的高度 , max( f [ j ] ) 就是求符合第j个方块的x,y面大于第i个方块的x,y面的高度数)。
最后记录最大的值就可以求解了。
代码如下:
#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
struct node
{
int x,y,h;
}block[100];
int ans[110];
int cmp(const void *a,const void *b)
{
struct node *x=(struct node*)a,*y=(struct node*)b;
if( x->x != y->x ) return y->x-x->x;
else if( x->y != y->y ) return y->y - x->y;
else if( x->h != y->h ) return y->h - x->h;
else return 0;
}
int swap(int &a,int &b)
{
if( a < b ) { int temp=a; a=b,b=temp; }
}
int main()
{
int n,all=0,i,j,k=1,max;
while( scanf("%d",&n)==1 && n )
{
for( i=0; i < 3*n; i+=3 )
{
scanf("%d%d%d",&block[i].x,&block[i].y,&block[i].h); //这是某一种规格的第一种形式x,y
block[ i+1 ].x = block[ i ].x, block[ i+1 ].y = block[ i ].h, block[ i+1 ].h = block[ i ].y;//第二种形式x,h
block[ i+2 ].x = block[ i ].y, block[ i+2 ].y = block[ i ].h, block[ i+2 ].h = block[ i ].x;//第三种形式y,h
swap( block[i].x ,block[i].y ); swap( block[i+1].x,block[i+1].y ); swap( block[i+2].x,block[i+2].y ); //把x,y中大的那一个放到前面
}
qsort(block,3*n,sizeof(struct node),cmp); //按x,y面的大小来进行排序
for(i=0;i<3*n;i++) ans[i]=block[i].h;
for(i=0,all=0;i<3*n;i++)
{
for(j=0,max=0;j<i;j++)
if( block[j].x > block[i].x && block[j].y > block[i].y && max < ans[j] ) max=ans[j]; //找f(j)的最大值
if( ans[i]+max > ans[i] ) ans[i]+=max;
if( ans[i] > all ) all=ans[i];
}
printf("Case %d: maximum height = %d\n",k++,all);
}
return 0;
}