问题描述
如果一些边长互不相同的正方形,可以恰好拼出一个更大的正方形,则称其为完美正方形。
历史上,人们花了很久才找到了若干完美正方形。
比如:如下边长的 22 个正方形:2 3 4 6 7 8 12 13 14 15 16 17 18 21 22 23 24 26 27 28 50 60
如图这样组合,就是一种解法。
此时,紧贴上边沿的是:60 50,紧贴下边沿的是:26 28 17 21 18
22 阶完美正方形一共有8种。
右边的组合是另一种:2 5 9 11 16 17 19 21 22 24 26 30 31 33 35 36 41 46 47 50 52 61
如果告诉你该方案紧贴着上边沿的是从左到右依次为:47 46 61,你能计算出紧贴着下边沿的是哪几个正方形吗?
答案提交
请提交紧贴着下边沿的正方形的边长,从左到右,用空格分开。
不要填写任何多余的内容或说明文字。
答案:50 33 30 41
题解
DFS:
∵ 边长:47 + 16 + 61 = 154
∴ 将该正方形看成一个 154 × 154 的网格即可
#include <iostream>
using namespace std;
const int N = 200;
int g[N][N];
bool st[N], cnt[N];
int s[22] = {2, 5, 9, 11, 16, 17, 19, 21, 22, 24,
26, 30, 31, 33, 35, 36, 41, 46, 47, 50, 52, 61};
bool judge(int x, int y, int len) // 判断从 (x, y) 起,能否添加边长为 len 的正方形
{
if(x + len - 1 > 154 || y + len - 1 > 154) return false; // 出界
for (int i = x; i < x + len; i ++)
for (int j = y; j < y + len; j ++)
if(g[i][j]) return false; // 该点已经被包含在其它正方形内
return true;
}
void add(int x, int y, int len, int num) // 从 (x, y) 起,添加边长为 len 的正方形
{
for (int i = x; i < x + len; i ++)
for (int j = y; j < y + len; j ++)
g[i][j] = num;
}
void dfs(int x, int y)
{
if(y == 154) x ++, y = 1; // 换行
if(x == 155) // 输出答案
{
for (int i = 1; i <= 154; i ++)
if(!cnt[g[154][i]])
{
cout << g[154][i] << " ";
cnt[g[154][i]] = true;
}
}
if(!g[x][y]) // 该点还未被填充
{
for (int i = 0; i < 22; i ++)
if(!st[i] && judge(x, y, s[i]))
{
st[i] = true;
add(x, y, s[i], s[i]);
dfs(x, y + 1);
add(x, y, s[i], 0); // 回溯
st[i] = false;
}
}
else dfs(x, y + 1);
}
int main()
{
add(1, 1, 47, 47);
add(1, 48, 46, 46);
add(1, 94, 61, 61);
dfs(1, 1);
return 0;
}
ps:当时不会有人能画出来吧🤣