经过观察和样例和数据范围,发现此题不太好找规律,数据范围小,故可以用dfs+回溯解决
确定返回条件:
1.如果当前的使用的地砖数大于存的最小答案,就可以回溯,不再向下搜
2.如果没在1处返回并且当前铺的面积已经等于总面积n*m,便记录答案,返回
搜索:
先确定当前正方形的起点,循环枚举他的最大边长(边长不超过任一总长且此正方形所在位置还未被覆盖)。
循环中,如果满足刚才的条件,就把正方形所在位置填1,并找到下一个还未被填的起点继续dfs。
在回溯中,只需要将上一步填过1的地方填0释放即可。
class Solution {
public:
bool vis[15][15];
int ans;
int x2,y2;
int tilingRectangle(int n, int m) {
ans=n*m;
memset(vis,false,sizeof(vis));
dfs(0,0,0,0,n,m);
return ans;
}
void fill(int x1,int y1,int i1,bool sta) //填值
{
for(int i=x1;i<x1+i1;i++)
{
for(int j=y1;j<y1+i1;j++)
{
vis[i][j]=sta;
}
}
}
void find(int n,int m) //找到下一个还未填1的位置
{
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(vis[i][j]==false)
{
x2=i;
y2=j;
return ;
}
}
}
}
bool check(int x1,int y1,int i1) //检查当前正方形是否能填
{
for(int i=x1;i<x1+i1;i++)
{
for(int j=y1;j<y1+i1;j++)
{
if(vis[i][j]==true) return 0;
}
}
return 1;
}
void dfs(int x,int y,int s,int cur,int n,int m)
{
if(cur>=ans) return; //剪枝
if(s==n*m) //满足条件
{
ans=cur;
return;
}
for(int i=min(n-x,m-y);i>0&&check(x,y,i);i--) //枚举所在起点的边长
{
fill(x,y,i,true); //填1
find(n,m); //找到下一个还未填的位置
dfs(x2,y2,s+i*i,cur+1,n,m); //dfs
fill(x,y,i,false); //回溯,填0
}
}
};