标签:
题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=2589
题目大意:
有一个边长为L的正方形有L*L个小正方形,将N个小石子放在N个小正方形中,给你N个小石子所放
位置,那么问题来了:能否将这个变成为L的正方形分割成N个正方形,使得每个正方形中都含有1个
小石子,并且这N个正方形正好构成整个正方形。
测试样例1说明:
边长为5的大正方形里有8个小石子,正好能将大正方形分解成8个小正方形,且每个正方形中有1个
小石子。
思路:
用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; }
标签:
原文地址:http://blog.csdn.net/lianai911/article/details/43667249