【HDU】1069 Monkey and Banana
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1069
很好的DP题目!
初看到的时候没有感觉,除了蒙……
经过merlininice师父的分析,醍醐灌顶啊!!! 同时也更清晰的明白了将问题转化的重要性。(千万不要做个直脑筋的人那,肯定会被坑死的!)
分析:
依题目要求,砖块的任意一个面都能作为底面,垫在下方的底面的长和宽都必须严格大于上面的底面的长和宽。要求求出最高的高度。
如果没有红色字体的要求,这个问题可能就会比较容易处理:很明显,只要先将所有的砖块按其长(或者宽)进行升序排序,接着处理宽值,那么问题就转化为LIS(Longest Increasing Subsequence)最长上升子序列或者 最长不下降子序列的问题了。
但是增加了红色字体的要求,困难点在于究竟要如何选择一块砖的3条边作为长、宽、高呢?(我最初的疑惑点)… … …
merlininice师父只是淡淡说了一句:那你就把一块砖当3块砖来用,3块砖固定长、宽、高,然后按照刚才的思路处理问题。
于是于是,继2次wa(小问题、大问题不断啊!求1Y啊~~)
又要用我的 “ 自我牺牲 ” 来警戒大家了:
qsort(q,cur,sizeof(q[0]),cmp);
memset(dp,0,sizeof(dp)); --->错误点!dp的初始值不能等于零!展开分析:最优解有可能不是以dp[0]为首展开的!所以所有的dp[i]都应该初始化为相应的q[i].h~~ 在LIS问题中dp[]数组的初始化往往都是对应的值,而不是0!
dp[0] = q[0].h;
int max = 0;
for(i=0; i<cur; ++i){
// cout<<q[i].x<<" "<<q[i].y<<endl;
for(j=0; j<i; ++j){
if(q[i].y<q[j].y) dp[i] = dp[i] > dp[j]+q[i].h ? dp[i] : dp[j]+q[i].h;
}
max = max > dp[i] ? max : dp[i];
}
恩,2次wa提交的居然是一样的代码…… = =
接下来就看代码吧~
在输入的时候将砖块拆分成3个固定长、宽、高的砖块。
Input
1 int cur = 0; 2 for(i=0; i<n; ++i) { 3 scanf("%d %d %d",&a,&b,&c); 4 q[cur].x = a>b ? a: b; 5 q[cur].y = a>b ? b: a; 6 q[cur].h = c; 7 cur ++; 8 q[cur].x = c>b ? c: b; 9 q[cur].y = c>b ? b: c; 10 q[cur].h = a; 11 cur ++; 12 q[cur].x = a>c ? a: c; 13 q[cur].y = a>c ? c: a; 14 q[cur].h = b; 15 cur ++; 16 }
处理好上面的问题后就是先对x、y的某个进行升序排序后,进行O(n^n)的LIS的处理。
View Code
1 qsort(q,cur,sizeof(q[0]),cmp); 2 3 int max = 0; 4 for(i=0; i<cur; ++i){ 5 dp[i]=q[i].h; 6 for(j=0; j<i; ++j){ 7 if(q[i].y<q[j].y && q[i].x<q[j].x) dp[i] = dp[i] > dp[j]+q[i].h ? dp[i] : dp[j]+q[i].h; 8 } 9 max = max > dp[i] ? max : dp[i]; 10 } 11 printf("Case %d: maximum height = %d\n",++k, max);

浙公网安备 33010602011771号