紫书 例题7-14 UVa 1602(搜索+STL+打表)

这道题想了很久不知道怎么设置状态,怎么拓展,怎么判重, 最后看了这哥们的博客 终于明白了。

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;
}

posted @ 2018-04-07 11:39  Sugewud  阅读(113)  评论(0编辑  收藏  举报