笛卡尔坐标变换的基本知识:
坐标标准化:找到最小的x,y值,然后让所有坐标点减去该最小值,得到标准化的坐标
平移:将所有坐标标准化之后,就无需再判断平移
翻转:关于x轴的翻转(x,y)-> (x,-y); 关于y轴的翻转(x,y) ->(-x,y); 关于y的翻转是x轴翻转后旋转270度得到,反之亦然。
旋转:顺时针旋转 90度(x,y) -> (y,-x); 逆时针旋转就是顺时针的补角;
模板:
标准化笛卡尔坐标;
判重;
操作(平移,翻转,旋转);
再次标准化笛卡尔坐标;
再次判重;
笛卡尔坐标状态的判重:当前的状态平移到坐标原点,每次都顺时针旋转90度,检查是否和当前的同一属性的状态集合中出现的有重复。如果均没有,将该连通块沿x轴翻转后,再依次顺时针旋转90度判断,如果均没有,就表示这是一种新的状态,加入到同一属性的状态集合中即可。
set容器: 本身是有序的,并且可以判重操作(无论是什么数据类型,只要内部实现了 <运算符);
打表: 题目数据不大时,把所有答案记录下来;
判断在一个i * j的范围内,一些连通的笛卡尔坐标是否越界:
maxX: 连通的笛卡尔坐标的最大x值
maxY: 连通的笛卡尔坐标的最大y值
if(min(maxX,maxY) < min(i,j) && max(maxX,maxY) < max(i,j))
在范围内;
else
越界;
根据紫书代码修改:
#include
#include
#include
#include
#include
#include
#include
using namespace std;
struct Cell
{
int x, y;
Cell(int _x,int _y):x(_x),y(_y){}
bool operator <(const Cell& t1)const {
return x > t1.x || (x == t1.x && y > t1.y);
}
};
//数据类型定义
**typedef set<Cell> successionBlocks;**
set<successionBlocks> pd[11];
//宏定义
**#define FOR_CELL(c,q) for (successionBlocks::const_iterator c = (q).begin(); c != (q).end(); (c)++)**
int dir[4][2] = { {-1,0},{1,0},{0,-1},{0,1} };
int ans[11][11][11];
int N = 11;
//标准化
**inline successionBlocks init(const successionBlocks& newB) {
int minx, miny;
minx = newB.begin()->x;
miny = newB.begin()->y;
FOR_CELL(it, newB) {
minx = min(minx, it->x);
miny = min(miny, it->y);
}
successionBlocks b;
FOR_CELL(it, newB) {
b.insert(Cell(it->x - minx, it->y - miny));
}
return b;
}**
//旋转
**inline successionBlocks rotate(const successionBlocks& newB) {
successionBlocks b;
FOR_CELL(it, newB) {
b.insert(Cell(it->y, -(it->x)));
}
return init(b);
}**
//翻转
**inline successionBlocks flip(const successionBlocks& newB) {
successionBlocks b;
FOR_CELL(it, newB) {
b.insert(Cell(it->x, -(it->y)));
}
return init(b);
}**
void check_unique(const successionBlocks& p0, const Cell &c) {
successionBlocks b = p0;
b.insert(c);
b = init(b);
int size = b.size();
for (int i = 0; i < 4; i++) {
if (pd[size].count(b))
return ;
b = rotate(b);
}
b = flip(b);
for (int i = 0; i < 4; i++) {
if (pd[size].count(b))
return;
b = rotate(b);
}
pd[size].insert(b);
}
void Generate() {
successionBlocks first;
first.insert(Cell(0, 0));
pd[1].insert(first);
for (int i = 2; i < N; i++) {
for (set<successionBlocks>::iterator it = pd[i - 1].begin(); it != pd[i - 1].end(); it++) {
for (successionBlocks::iterator it2 = it->begin(); it2 != it->end(); it2++) {
for (int j = 0; j < 4; j++) {
Cell newc(it2->x + dir[j][0], it2->y + dir[j][1]);
if (it->count(newc) == 0) check_unique(*it, newc);
}
}
}
}
for (int i = 1; i < N; i++) {
for (int j = 1; j < N; j++) {
for (int k = 1; k < N; k++) {
int count = 0;
for (set<successionBlocks>::iterator it = pd[k].begin(); it != pd[k].end(); it++) {
int maxx = -1000;
int maxy = -1000;
for (successionBlocks::iterator it2 = it->begin(); it2 != it->end(); it2++) {
maxx = max(maxx, it2->x);
maxy = max(maxy, it2->y);
}
//判断在一个i * j的范围内,一些连通的笛卡尔坐标是否越界;
if (min(maxx,maxy) < min(j,i) && max(maxx,maxy) < max(j,i))
count++;
}
ans[k][i][j] = count;
}
}
}
}
int main() {
Generate();
int n, h, l;
while (cin >> n >> h >> l && n != 0) {
cout << ans[n][h][l] << endl;
}
return 0;
}