本帖最后由 guosl 于 2022-10-3 22:20 编辑
应用状态压缩的动态规划来做。
答案:20574308184277971#include <iostream>
#include <cstring>
using namespace std;
struct stObj
{
short L[3];//三层布局
stObj(void)
{
memset(L, 0, 3 * sizeof(short));
}
};
stObj bobj[6];//最基本的六种形状
unsigned long long f[13][512][512];
void dfs(int k, stObj oObj, stObj nObj, int c)//用深搜来找出扩充
{
if (nObj.L[0] == 511)
{
f[k][nObj.L[1]][nObj.L[2]] += f[k - 1][oObj.L[0]][oObj.L[1]];//递推方程
return;
}
if (c >= 9)
return;
if ((nObj.L[0] & (1 << c)) != 0)
return dfs(k, oObj, nObj, c + 1);
for (int i = 0; i < 6; ++i)//查找可以铺设的块
{
stObj tobj = bobj[i];
int d = c;
if ((tobj.L[0] & 1) == 0)
--d;
if (d < 0)
continue;
//对基本块进行平移
tobj.L[0] = (tobj.L[0] << d);
tobj.L[1] = (tobj.L[1] << d);
tobj.L[2] = (tobj.L[2] << d);
if ((tobj.L[0] & 512) != 0 || (tobj.L[1] & 512) != 0 || (tobj.L[2] & 512) != 0)//检查是否出头
continue;
if ((nObj.L[0] & tobj.L[0]) == 0 && (nObj.L[1] & tobj.L[1]) == 0 && (nObj.L[2] & tobj.L[2]) == 0)//检查是否有重叠
{
//铺下去
stObj tt = nObj;
tt.L[0] |= tobj.L[0];
tt.L[1] |= tobj.L[1];
tt.L[2] |= tobj.L[2];
dfs(k, oObj, tt, c + 1);//查找新的块
}
}
}
int main(void)
{
//形状一
bobj[0].L[0] = 2;
bobj[0].L[1] = 3;
bobj[0].L[2] = 0;
//形状二
bobj[1].L[0] = 1;
bobj[1].L[1] = 3;
bobj[1].L[2] = 0;
//形状三
bobj[2].L[0] = 3;
bobj[2].L[1] = 2;
bobj[2].L[2] = 0;
//形状四
bobj[3].L[0] = 3;
bobj[3].L[1] = 1;
bobj[3].L[2] = 0;
//形状五
bobj[4].L[0] = 1;
bobj[4].L[1] = 1;
bobj[4].L[2] = 1;
//形状六
bobj[5].L[0] = 7;
bobj[5].L[1] = 0;
bobj[5].L[2] = 0;
f[0][0][0] = 1;
//下面部分是可以用OpenMP进行平行化处理的,不过本身耗时不多,就不做了
for (int k = 1; k <= 12; ++k)
{
for (int i = 0; i < 512; ++i)
f[k][i][0] += f[k - 1][511][i];
for (int i = 0; i < 511; ++i)//枚举状态
{
for (int j = 0; j < 512; ++j)
{
stObj obj;
obj.L[0] = i;
obj.L[1] = j;
dfs(k, obj, obj, 0);//递归铺设
}
}
}
cout << f[12][0][0] << endl;
return 0;
}
|