题目描述
园区打算购买一块 m×n 大小的土地,用于建设新园区。希望将这块土地规划为尽可能少的正方形区域。规划完这块土地后,应该满足一个状态:没有任何一个正方形能放入。
输入描述
输入第一行为一个整数 m。
输入第二行为一个整数 n。
其中 1 ≤ m ≤ 13,1 ≤ n ≤ 13。
输出描述
输出为一个整数,表示最少能规划块区域的数量。
用例输入
3
2
3
最少能规划块3个区域。 先规划1个2×2,剩下区域规划2个 1×1。
13
11
6
解题思路
本题要求使用搜索+剪枝策略解决一个NP问题,即在给定的m×n大小的土地上规划尽可能少的正方形区域。在这里采用搜索+剪枝的方法来求解。这种方法虽然可能无法保证找到最优解,但在实际比赛中可以作为一种有效的策略来尽可能拿到分数。
搜索策略
-
定义状态:使用一个二维数组
g[i][j]
来表示土地上的点是否已经被分割为了一个正方形,false
表示未分割,true
表示已分割。 -
搜索过程:从左上角开始,找到一个未被分割的点(即
g[i][j] = false
),尝试以该点为正方形的左上角点分割正方形。 -
枚举正方形边长:尝试分割不同边长的正方形,从大到小枚举,以便尽早找到一个较小的答案。
-
标记已分割区域:将分割的区域标记为
true
,表示已经分割了正方形。 -
递归搜索:分割完成后,递归地对剩余未分割区域进行同样的操作,直到所有区域都被分割或无法再分割为止。
剪枝策略
-
记录最小答案:在搜索过程中,记录当前已经找到的最小分割正方形数量
ans
。如果当前统计的分割数量cnt
大于等于ans
,则停止进一步搜索。 -
从大到小枚举:在枚举分割正方形的边长时,从大到小枚举,这样能够尽早找到一个较小的答案,从而在后续搜索中减少搜索量。
-
边界检查:在尝试分割正方形时,检查是否超出土地边界,如果超出则不进行分割。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include<algorithm>
#include<string>
#include<vector>
#include<unordered_map>
#include<unordered_set>
#include<queue>
#include<set>
#include<list>
#include<sstream>
#include<bitset>
#include<stack>
#include<climits>
using namespace std;
bool g[15][15];
int m, n;
int res = INT_MAX;
// 左上角顶点为x y 长度为len的正方形可否填充
bool check(int x, int y, int len) {
for (int i = 0; i < len; ++i) {
for (int j = 0; j < len; ++j) {
if (g[x + i][y + j]) return false;
}
}
return true;
}
// 取反
void fill_g(int x, int y, int len) {
for (int i = 0; i < len; ++i) {
for (int j = 0; j < len; ++j) {
g[x + i][y + j] =!g[x + i][y + j];
}
}
}
// 从 x y开始枚举 cnt当前填充的正方形数量
void dfs(int x, int y, int cnt) {
if (cnt >= res) return;
if (x == m) {
res = min(res, cnt);
return;
}
bool flag = true;
//只枚举列
for (int j = y; j < n; j++) {
if (!g[x][j]) {
flag = false;
// 右边和下面空余的长度 数组大小为m n
for (int k = min(m - x, n - j); k >= 1; k--) {
if (check(x, j, k)) { //可以填充
fill_g(x, j, k);
dfs(x, j + k, cnt + 1);
fill_g(x, j, k);
}
}
break;
}
}
// 行全部满了
if (flag) dfs(x + 1, 0, cnt);
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> m >> n;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
g[i][j] = false;
}
}
dfs(0, 0, 0);
cout << res;
}