hdu1069 http://acm.hdu.edu.cn/showproblem.php?pid=1069
题意:
一群研究人员设计了一个检测猴子IQ的实验。他们将一个香蕉放在了房子的屋顶,同时,给小猴子一些木块。如果猴子足够聪明,他将可以用一个木块叠加另一个木块来构建一个木塔来够到香蕉。
研究人员有N种木块,无限制提供各种木块。第i个木块是一个长方体,坐标是(xi,yi,zi)。木块摆放可以调整方向,任意两条边可以当做长方体的底边,那么另一边是高。
他们想知道最高可以搭建多少来够到房顶。问题是:在构建木塔时,一个木块要完全覆盖上面一个木块,只要上面的木块的底座两边要都小于下面木块底座的两边(我写的代码中只需上面木块的最长底边小于下面木块的最长边,另一条上面的小于下面的就可以了),因为小猴子需要可以踩的地方。这意思是,例如,木块有同样长度的底边,就不能叠。
数据:N种木块,每种木块的x, y, z;
每种木块可以无数次取,但仔细想想其实每种木块最多拿2块,比如说6 8 10,有三种情况,第一种底边6 8,高10,第二种底边6 10,高8,第三种底边8 10,高6。但据题意,第一种可以和第三种一起拿,而第二种只能单独拿,因此最多拿两块,而且不能重复。
其实dp的一种题目,可以将三种都存入,然后就变成了01背包问题啦!之后就是我们熟悉的回溯过程了
还有我的point数组x要大于等于y,这样在比较是否可以搭在j上时,只需判断(point[i].x < point[j].x && point[i].y < point[j].y)就好了^^
这道题不算难,是一种经典题型,我RE了两发,等我将dp数组从二维改为一维就AC了,为什么现在也不知道==
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
using namespace std;
struct Node
{
int x, y;
int high;
}point[1100];
int dp[1100];
int comp(struct Node a, struct Node b)
{
if(a.x == b.x)
{
if(a.y == b.y)
{
a.high > b.high;
}
return a.y > b.y;
}
return a.x > b.x;
}
int main()
{
int n, m;
int i, j, k, mmax, Max;
int x, y, z;
m = 0;
while(~scanf("%d", &n) && n)
{
k = 0; m++;
memset(point, 0, sizeof(point));
for(i = 0; i < n; i++)
{
scanf("%d%d%d", &x, &y, &z);
if(x == y && y == z)
{
point[k].x = point[k].y = point[k].high = x;
k++;
}
else
{
for(j = 0; j < 3; j++)
{
if(j == 0)
{
point[k].x = max(x, y);
point[k].y = min(x, y);
point[k].high = z;
k++;
}
if(j == 1)
{
point[k].x = max(y, z);
point[k].y = min(y, z);
point[k].high = x;
k++;
}
if(j == 2)
{
point[k].x = max(z, x);
point[k].y = min(z, x);
point[k].high = y;
k++;
}
}
}
}
sort(point, point+k, comp);
Max = point[0].high;
for(i = 0; i < k; i++)
{
dp[i] = point[i].high;
mmax = point[i].high;
for(j = 0; j < i; j++)
{
z = point[i].high;
if(point[i].x < point[j].x && point[i].y < point[j].y)
{
z += dp[j];
}
mmax = max(z, mmax);
}
dp[i] = mmax;
Max = max(Max, mmax);
}
cout << "Case " << m << ": maximum height = " << Max << endl;
}
return 0;
}
请多指教^^