笛卡尔坐标变换: UVA1602

笛卡尔坐标变换的基本知识:
坐标标准化:找到最小的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;
}

你可能感兴趣的:(笔记,c++,算法)