首先这道题目先要理解题目的意思。
用一些方块堆塔,给出的每种方块个数是无限的,只有满足长宽都小于下面一个方块的方块才能摆上去。
首先这道题需要一个转化。
每个方块有3个不同的面,每个面长宽交换,一共每个方块最多有6种情况。
X Y Z
1 2 3
2 1 3
3 1 2
1 3 2
2 3 1
3 2 1
如果长宽高有相同的部分还可以减少一些情况
然后对面积,长,宽,从小到大排序。
这步做完dp的准备才算完成。
下面分析dp部分。
如果不用dp,用贪心先试试,先把最大的面积放在下面,然后循环面积比他小的,如果满足长宽都小就摆上去,循环一遍摆完为止。
for(n->1)
{
for(n-1->1)
{
max +=z;
}
}
看上去貌似是可以的,但是其实是不行的,因为你摆了n-1之后,能不能摆n-3了,如果不能,你就不知道n-3和n-4的组合是不是比摆n-1要好了,所以贪心失败。
dp试试
从小到大,先摆最小的,然后用下一个,循环比所有他小的(之前已经摆好了),其中dp【】数据最优的,保存在当前dp【】数组中并且加上当前的方块高度。
状态转移方程
dp【now】 = max(for(now->1)循环中dp【】值最大的) + bolck【now】;
初始值
全部为0
下面给出dp的代码和贪心的代码
#include<cstdio> #include<cstdlib> #include<iostream> #include<algorithm> using namespace std; /*dp,hdu1069*/ int dp[500];//动态规划的数组 struct block { int x;//长 int y;//宽 int z;//高 int s;//面积 }; int cmp(const void * a, const void * b) { struct block * p2 = (struct block *)a; struct block * p1 = (struct block *)b; if(p1->s != p2->s) return p2->s - p1->s; else if(p1->x != p2->x) return p2->x - p1->x; else return p2->y - p1->y; } int main() { int n;//方块个数 int i,j;//循环变量 int number=0;//记录可行方块数,一个方块最多有6钟可行方案 int maxNumber=0;//记录结果 int reslut=1;//记录次数 int x,y,z;//用户输入 int tempMax,tempX,tempY;//临时变量 struct block blocks[500];//保存所有情况方块 while (true) { cin>>n; if(n==0) break; number=0; for (i = 0; i < n; i++) { cin>>x>>y>>z; //记录6钟情况 if(x==y&&y==z) { blocks[number].x = x; blocks[number].y = y; blocks[number].z = z; blocks[number].s = x*y; number++; } else { if(x==y) { blocks[number].x = x; blocks[number].y = y; blocks[number].z = z; blocks[number].s = x*y; number++; } else { blocks[number].x = x; blocks[number].y = y; blocks[number].z = z; blocks[number].s = x*y; number++; blocks[number].x = y; blocks[number].y = x; blocks[number].z = z; blocks[number].s = x*y; number++; } if(x==z) { blocks[number].x = x; blocks[number].y = z; blocks[number].z = y; blocks[number].s = x*z; number++; } else { blocks[number].x = x; blocks[number].y = z; blocks[number].z = y; blocks[number].s = x*z; number++; blocks[number].x = z; blocks[number].y = x; blocks[number].z = y; blocks[number].s = x*z; number++; } if(y==z) { blocks[number].x = z; blocks[number].y = y; blocks[number].z = x; blocks[number].s = y*z; number++; } else { blocks[number].x = z; blocks[number].y = y; blocks[number].z = x; blocks[number].s = y*z; number++; blocks[number].x = y; blocks[number].y = z; blocks[number].z = x; blocks[number].s = y*z; number++; } } } //对于s-x-y小到大排序所有方块 qsort(blocks, number, sizeof(block), cmp); maxNumber = 0; tempMax=0; dp[0] = blocks[0].z; maxNumber = dp[0]; for (i = 1; i < number; i++) { dp[i]=blocks[i].z; tempMax=0; tempX=blocks[i].x; tempY=blocks[i].y; for (j = i-1; j >= 0; j--) { if(tempX > blocks[j].x && tempY > blocks[j].y) { if(tempMax < dp[j]) tempMax=dp[j]; } } dp[i] += tempMax; if(dp[i] > maxNumber) maxNumber=dp[i]; } printf("Case %d: maximum height = %d\n",reslut,maxNumber); reslut++; } return 0; }
贪心
#include<cstdio> #include<cstdlib> #include<iostream> #include<algorithm> using namespace std; /*贪心,失败,hdu1069*/ struct block { int x;//长 int y;//宽 int z;//高 int s;//面积 }; int cmp(const void * a, const void * b) { struct block * p1 = (struct block *)a; struct block * p2 = (struct block *)b; if(p1->s != p2->s) return p2->s - p1->s; else if(p1->x != p2->x) return p2->x - p1->x; else return p2->y - p1->y; } int main() { int n;//方块个数 int i,j;//循环变量 int number=0;//记录可行方块数,一个方块最多有6钟可行方案 int maxNumber=0;//记录结果 int reslut=1;//记录次数 int x,y,z;//用户输入 int tempMax,tempX,tempY; struct block blocks[500]; while (true) { cin>>n; if(n==0) break; number=0; for (i = 0; i < n; i++) { cin>>x>>y>>z; //记录6钟情况 if(x==y&&y==z) { blocks[number].x = x; blocks[number].y = y; blocks[number].z = z; blocks[number].s = x*y; number++; } else { if(x==y) { blocks[number].x = x; blocks[number].y = y; blocks[number].z = z; blocks[number].s = x*y; number++; } else { blocks[number].x = x; blocks[number].y = y; blocks[number].z = z; blocks[number].s = x*y; number++; blocks[number].x = y; blocks[number].y = x; blocks[number].z = z; blocks[number].s = x*y; number++; } if(x==z) { blocks[number].x = x; blocks[number].y = z; blocks[number].z = y; blocks[number].s = x*z; number++; } else { blocks[number].x = x; blocks[number].y = z; blocks[number].z = y; blocks[number].s = x*z; number++; blocks[number].x = z; blocks[number].y = x; blocks[number].z = y; blocks[number].s = x*z; number++; } if(y==z) { blocks[number].x = z; blocks[number].y = y; blocks[number].z = x; blocks[number].s = y*z; number++; } else { blocks[number].x = z; blocks[number].y = y; blocks[number].z = x; blocks[number].s = y*z; number++; blocks[number].x = y; blocks[number].y = z; blocks[number].z = x; blocks[number].s = y*z; number++; } } } qsort(blocks, number, sizeof(block), cmp); maxNumber = 0; tempMax=0; tempX=0; tempY=0; for (i = 0; i < number; i++) { tempMax=blocks[i].z; tempX=blocks[i].x; tempY=blocks[i].y; for (j = i+1; j < number; j++) { if(tempX > blocks[j].x && tempY > blocks[j].y) { tempX=blocks[j].x; tempY=blocks[j].y; tempMax += blocks[j].z; } } if(tempMax > maxNumber) maxNumber=tempMax; } printf("Case %d: maximum height = %d\n",reslut,maxNumber); reslut++; } return 0; }
经过实践,贪心可以满足前几组数据,但是最后一组数据就GG了
而且贪心和dp的效率在这里均为O(NlogN + N!)所以并没有快。
再一次证明dp确实很多时候比贪心好用。
但是其实最重要的是在dp之前对题目的分析,要把一个题目抽象到一组数,这个才是需要特别去考虑的事情,如果之前都想不到的话是肯定得不到最后的答案的。
时间: 2024-10-10 10:34:24