算法-堆方块的高度-记忆化搜索

该博客探讨了一种解决三维方块堆叠问题的算法,旨在找到最高可能的堆叠高度。通过考虑方块的旋转和选择,提出了使用记忆化搜索(Memoization)来优化递归搜索,避免超时。博主详细解释了状态表示、转移方程和关键函数,如`PutBelow`用于检查方块是否能放置。最后,给出了完整的C++代码实现,包括输入处理和主函数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意

有若干的方块堆叠,长宽均小于等于下面的方块,才能堆叠上去。方块可以任意旋转(长宽高任意切换)。每个输入的方块只能使用一次,但是多个输入的方块可以有相同长宽高。求可能堆叠的最高高度。
输入:
N(方块数目,1<=N<=20)
x1 y1 z1(第一个方块的长宽高)
x2 y2 z2(第二个方块的长宽高)

xN yN zN(第N个方块的长宽高)
输出:
Hmax

示例

示例1:
输入:
1
4 7 8
输出
8
实例2:
输入:
3
1 2 3
1 3 2
3 2 1
输出:
9
实例3:
输入:
3
55 10 9
4 7 8
1 3 2
输出:
66

分析

如果直接DFS,会超时
(20个方块*3个面,60树枝,20树层,60!)
–》
使用MEMO
–》
MEMO[1<<60]太大
–》
MEMO[20][3][1 << 20]

MEMO[20][3][1 << 20] 的说明:

已选择的方块[101011]
最上面的是[20][3] 有20种*3面
转移方程:已选方块去除最上面的,剩下的已选方块,每个都尝试一下,能不能将去除的方块放在自己上面。
MEMO[6][0][10111100], 10111100去掉第六块,变成00111100
00111100,第3、4、5、6块每个方块、每个面,都尝试看看能不能把[6][0]放在自己上面
MEMO[3][0][00111100]
MEMO[3][1][00111100]
MEMO[3][2][00111100]
MEMO[4][0][00111100]
MEMO[4][1][00111100]
MEMO[4][2][00111100]
MEMO[5][0][00111100]
MEMO[5][1][00111100]
MEMO[5][2][00111100]
MEMO[6][0][00111100]
MEMO[6][1][00111100]
MEMO[6][2][00111100]
这些取最大值

题解

#define MIN(a,b) (a)<(b)?(a):(b)
#define MAX(a,b) (a)>(b)?(a):(b)
int memo[20][3][1 << 20] = { 0 };
int N;
int cube[20][3];

bool inState(int i,int S)
{
	if ((S & (1 << i) )== 0)
		return false;
	return true;
}
int addState(int i, int S) { S = (S | (1 << i)); return S; }
int delState(int i, int S) { S -= (S & (1 << i)); return S;}

bool PutBelow(int cubup, int rotateup, int cubbelow, int rotatebelow)
{
	int x1 = cube[cubup][(rotateup + 1) % 3];
	int y1 = cube[cubup][(rotateup + 2) % 3];
	int x2 = cube[cubbelow][(rotatebelow + 1) % 3];
	int y2 = cube[cubbelow][(rotatebelow + 2) % 3];
	if (x1 <= x2 && y1 <= y2 )
	{
		return true;
	}
	if (y1 <= x2 && x1 <= y2)
	{
		return true;
	}
	return false;
}
//curstate,last cub is cubNum of rotate,return MaxRes
//N=4  1 2 3  4 5 6  7 8 9  3 3 3
//curstate=6->0110->cub1 cub2 is selected, cub0,cub3 is not
//cubNum =1,rotate=1-->cub1 is at rear,height is 8;lenth and width is at ease
int dfs(int cubNum,int rotate,int curstate)   
{
	if (memo[cubNum][rotate][curstate] != 0)return memo[cubNum][rotate][curstate];

	int Nextstate = delState(cubNum, curstate);
	if (Nextstate == 0)
	{
		memo[cubNum][rotate][curstate] = cube[cubNum][rotate];
		return memo[cubNum][rotate][curstate];
	}

	int k = 0;
	int res = -1;
	int nextrot;
	for (k = 0; k < N; k++)
	{
		if(inState(k, Nextstate))
		for (nextrot=0; nextrot<3; nextrot++)
		{
			if (true==PutBelow(cubNum, rotate, k, nextrot))
				res = MAX(res, dfs(k, nextrot, Nextstate));
		}
		if (Nextstate < (1 << k))break;
	}
	if (res != -1)
	{
		memo[cubNum][rotate][curstate] = res+cube[cubNum][rotate];
		return memo[cubNum][rotate][curstate];
	}
	if (res == -1)
		return memo[cubNum][rotate][curstate] =-1;
}
void input()
{
	int i = 0;
	scanf("%d",&N);
	for (i = 0; i < N; i++)
	{
		scanf("%d", &cube[i][0]);
		scanf("%d", &cube[i][1]);
		scanf("%d", &cube[i][2]);
	}
}
/*
1
4 7 8
1
7 8 4
1
8 4 7
3
55 10 9    4 7 8  1 3 2
3
1 2 3   1 3 2      1 2 3
15
55 10 9  4 7 8  1 3 2  44 43 45   22 21 24  1 28  88  6 1 26  34 41 67   2 56 73  43 45 22  21 24 1  28 4 88  6 1 26  13 35 77  23 4 9  
*/
int main()
{
	input();
	int statenum = 1 << N;
	int i;
	int j;
	int rotate = 0;
	int res = 0;
	for (i = 0; i < N; i++)
	{
		for (j = 0; j < statenum; j++)  //00  01  10  11 -->4==1<<2-->0-3
		{
			if (false == inState(i, j))
				continue;
			for (rotate = 0; rotate < 3; rotate++)
			{
				res = MAX(res, dfs(i, rotate,j));
			}
		}
		
	}
	return res;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值