题目链接:

​http://acm.hdu.edu.cn/showproblem.php?pid=2589​


题目大意:

有一个边长为L的正方形有L*L个小正方形,将N个小石子放在N个小正方形中,给你N个小石子所放

位置,那么问题来了:能否将这个变成为L的正方形分割成N个正方形,使得每个正方形中都含有1个

小石子,并且这N个正方形正好构成整个正方形。

测试样例1说明:

边长为5的大正方形里有8个小石子,正好能将大正方形分解成8个小正方形,且每个正方形中有1个

小石子。

HDU2589 正方形划分【DFS】_ios


思路:

用DFS来做这道题。用Num[i][j]来表示从(1,1)到(i,j)的矩形中有多少个小石子(用来计算小正方形

中含有的小石子数),用vis[][]表示将包含1个小石子的正方形区域覆盖,用x,y来表示当前分解的正

方形的左上角坐标,k表示正方形的边长。每次找到没有覆盖的区域,记录坐标(x,y),开始遍历小

正方形的边长,直到找到刚好包含1个小石子的正方形区域,将其覆盖,然后接着深搜找到没有覆盖

的区域……如果没有找到刚好包含1个小石子的正方形区域,将其回溯到没有覆盖的状态继续深搜。

如果所有区域都能被覆盖,则说明满足条件,返回1。

注:设x1 = x + k,y1 = y + k。则计算从(x,y)到(x1,y1)的正方形中包含的小石子个数Count为:

Count = Num[x1][y1] - Num[x1][y-1] - Num[x-1][y1] + Num[x-1][y-1]。


AC代码:


#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;

int Map[22][22],Num[22][22],vis[22][22],L,N;

int DFS()
{
int x,y,flag = 1;
for(int i = 1; i <= L; ++i) //找到未分割正方形的位置坐标
{
if(!flag)
break;
for(int j = 1; j <= L; ++j)
{
if(!vis[i][j])
{
x = i;
y = j;
flag = 0;
break;
}
}
}

int k = 0;
while(x+k <= L && y+k <= L)
{
int x1 = x + k;
int y1 = y + k;
int Count = Num[x1][y1] - Num[x1][y-1] - Num[x-1][y1] + Num[x-1][y-1];//计算当前正方形内点的数目
if(Count > 1) //大于1不符合
break;
else if(Count == 1) //当前正方形中正好有1个点
{
for(int i = x; i <= x1; ++i) //填充该正方形
for(int j = y; j <= y1; ++j)
vis[i][j] = 1;
if(DFS()) //继续填充,满足所求条件返回1.
return 1;
for(int i = x; i <= x1; ++i) //回溯到未填充该正方形的状态
for(int j = y; j <= y1; ++j)
vis[i][j] = 0;
}

k++;
}

for(int i = 1; i <= L; ++i) //判断是否满足所求条件
for(int j = 1; j <= L; ++j)
if(!vis[i][j])
return 0;
return 1;
}

int main()
{
int T;
cin >> T;
while(T--)
{
cin >> L >> N;
memset(Num,0,sizeof(Num));
memset(vis,0,sizeof(vis));
memset(Map,0,sizeof(Map));

for(int i = 0; i < N; ++i)
{
int x,y;
cin >> x >> y;
Map[x][y] = 1;
}
for(int i = 1; i <= L; ++i)
for(int j = 1; j <= L; ++j)
Num[i][j] = Num[i-1][j] + Num[i][j-1] - Num[i-1][j-1] + Map[i][j];

if(DFS())
cout << "YES" << endl;
else
cout << "NO" << endl;
}

return 0;
}