第六届蓝桥杯(国赛)——完美正方形

问题描述
如果一些边长互不相同的正方形,可以恰好拼出一个更大的正方形,则称其为完美正方形。

历史上,人们花了很久才找到了若干完美正方形。

比如:如下边长的 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:当时不会有人能画出来吧🤣

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值