这道题想了很久不知道怎么设置状态,怎么拓展,怎么判重, 最后看了这哥们的博客 终于明白了。
https://blog.csdn.net/u014800748/article/details/47400557
这道题的难点在于怎么设置联通的状态,以及怎么拓展判重 .
(1)状态:这里状态先定义了一个格子cell, 有x和y坐标。然后set<cell>表示一个联通块, 再用set<set<cell>>表示n个连块可以组成的所有联通块, 这里是集合套集合。
(2)拓展:每个格子向四个方向拓展。平移方面用到了标准化,感性的认识就是把这个图形整个移到了左下角(具体看代码), 然后旋转,这里有一个规律,就是所有的格子都是 (x, y) -> (y, -x) ,每次执行都会旋转90度,记得最后返回的是标准化后的图形。翻转的话,沿x轴翻转, 即(x, y)-> (x, -y), 然后再旋转四次,其中旋转180度后即是y轴翻转的结果,已经包含在里面了,所以不用另外写。
(3)最后就是打表,在多组数据而每组数据程序运行的时候会做重复的事情的时候,用打表会比直接做更快一些
代码如下
#include<cstdio>
#include<algorithm>
#include<set>
#define REP(i, a, b) for(int i = (a); i < (b); i++)
using namespace std;
struct cell
{
int x, y;
cell(int x = 0, int y = 0) : x(x), y(y) {}
bool operator < (const cell& rhs) const
{
return x < rhs.x || (x == rhs.x && y < rhs.y); //固定写法
}
};
const int MAXN = 11;
typedef set<cell> piece;
int ans[MAXN][MAXN][MAXN];
set<piece> poly[MAXN];
int dir[4][2] = {0, 1, 0, -1, 1, 0, -1, 0};
inline piece normalize(piece p0)
{
int minx = 15, miny = 15; //最大也就10,这里表示最大值
for(auto& t : p0)
{
minx = min(minx, t.x);
miny = min(miny, t.y);
}
piece ret;
for(auto& t : p0) ret.insert(cell(t.x - minx, t.y - miny)); //这种遍历方式要c++11, 编译选项要加入-std=c++11
return ret;
}
inline piece rotate(piece p0)
{
piece ret;
for(auto& t : p0) ret.insert(cell(t.y, -t.x));
return normalize(ret);
}
inline piece file(piece p0)
{
piece ret;
for(auto& t : p0) ret.insert(cell(t.x, -t.y));
return normalize(ret);
}
void add(piece p0, cell c)
{
piece p = p0;
p.insert(c);
p = normalize(p);
int id = p.size();
REP(i, 0, 4)
{
if(poly[id].count(p)) return;
p = rotate(p);
}
p = file(p);
REP(i, 0, 4)
{
if(poly[id].count(p)) return;
p = rotate(p);
}
poly[id].insert(p);
}
void work()
{
piece start;
start.insert(cell(0, 0));
poly[1].insert(start);
REP(n, 2, MAXN)
for(auto& p : poly[n-1]) // 这里n-1,因为是从前一个拓展过来的
for(auto& t : p)
REP(i, 0, 4)
{
cell temp(t.x + dir[i][0], t.y + dir[i][1]);
if(!p.count(temp)) add(p, temp);
}
REP(n, 1, MAXN)
REP(w, 1, MAXN)
REP(h, 1, MAXN)
{
int cnt = 0;
for(auto& p : poly[n])
{
int maxx = 0, maxy = 0;
for(auto & t : p)
{
maxx = max(maxx, t.x);
maxy = max(maxy, t.y);
}
if(max(maxx, maxy) < max(w, h) && min(maxx, maxy) < min(w, h)) cnt++; //是否符合题目要求
}
ans[n][w][h] = cnt;
}
}
int main()
{
work();
int n, w, h;
while(~scanf("%d%d%d", &n, &w, &h))
printf("%d\n", ans[n][w][h]); //提前打表
return 0;
}