Lattice Animals UVA - 1602 

参考博客https://www.cnblogs.com/Rubbishes/p/7206869.html?utm_source=itdadao&utm_medium=referral

学到了很多,非常感谢

回朔法求解

通过对n-1个连通块进行扩展,可以得到所有的n个连通块的情形

这个题如果我们直接对输入数据进行处理,将会做许多重复工作,因为每次都要从1开始,到n结束,要枚举完1到n-1的所有情况

重复计算很多

所以选择打表预处理出所有的情况

状态的扩展是简单的,从连通块中任选一个,往四个方向扩展即可

为了实现,我们先去选择数据结构,连通块中任一块的位置用一个点描述,整个连通块需要存所有的点,那么可选的数据结构有数组,集合,我们选择集合

那么对于连通块的规模为n的所有连通块又拿什么存储呢?答案是集合

然后开始打表,这里还有一个问题,当我们扩展出一种新的状态的时,该怎么去判断它是否重复?

首先是平移操作,这里有一个技巧,就是我们让所有连通块中所有的点都移到左上角,然后去判断就行了

然后是旋转,在数学中坐标的顺时针90°旋转是(x, y)=>(y, -x),逆时针则是(x, y)=>(-y, x)

旋转后再判重即可

最后是翻转,公式是(x, y)=>(y, x),翻完判重

另外在自己编写时,出现一个问题,导致了程序崩溃

结果是

代码参考别人的写的

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<string>
#include<vector>
#include<set>
#pragma warning(disable:4996)
using namespace std;
#define ssit set< set<Cell> >::iterator
#define sit set<Cell>::iterator
const int MAXN = 10;
int ans[MAXN + 1][MAXN + 1][MAXN];
struct Cell
{
	int x, y;
	Cell(int x = 0, int y = 0) :x(x), y(y) {}
	bool operator<(const Cell &b) const {
		return (x == b.x&&y < b.y) || x < b.x;
	}
};
int dir[4][2] = { { 1,0 },{ 0,1 },{ -1,0 },{ 0,-1 } };
set<set<Cell>> Poly[MAXN + 1];
inline set<Cell> stardand(const set<Cell> & b)
{
	set<Cell> tmp;
	int minx = 0, miny = 0;
	for (sit it = b.begin(); it != b.end(); it++) {
		minx = min(minx, it->x);
		miny = min(miny, it->y);
	}
	for (sit it = b.begin(); it != b.end(); it++) tmp.insert(Cell(it->x - minx, it->y - miny));
	return tmp;
}
inline set<Cell> Rotate(const set<Cell> & s)
{
	set<Cell> tmp;
	for (sit it = s.begin(); it != s.end(); it++) tmp.insert(Cell(it->y, -it->x));
	return stardand(tmp);
}
inline set<Cell> Flip(const set<Cell> & s)
{
	set<Cell> tmp;
	for (sit it = s.begin(); it != s.end(); it++) tmp.insert(Cell(it->y, it->x));
	return stardand(tmp);
}
inline void IF_ADD(const set<Cell>& s, const Cell &New)
{

	set<Cell> tmp = s;
	tmp.insert(New);
	tmp = stardand(tmp);
	int n = tmp.size();
	for (int i = 0; i < 4; i++) {
		if (Poly[n].count(tmp)) return;
		tmp = Rotate(tmp);
	}
	tmp = Flip(tmp);
	for (int i = 0; i < 4; i++) {
		if (Poly[n].count(tmp)) return;
		tmp = Rotate(tmp);
	}
	Poly[n].insert(tmp);
}
void generate()
{
	set<Cell> fir; fir.insert(Cell(0, 0));
	Poly[1].insert(fir);   //只放一个方格时只有一种情况
	for (int i = 2; i <= MAXN; i++) {
		for (ssit it = Poly[i - 1].begin(); it != Poly[i - 1].end(); it++)
			for (sit it1 = it->begin(); it1 != it->end(); it1++) {
				for (int k = 0; k < 4; k++) {
					Cell tmp(it1->x + dir[k][0], it1->y + dir[k][1]);
					if (!it->count(tmp))  IF_ADD(*it, tmp);
				}
			}
	}
	for (int n = 1; n <= MAXN; n++)
		for (int w = 1; w <= MAXN; w++)
			for (int h = 1; h <= MAXN; h++) {
				int cnt = 0;
				for (ssit it = Poly[n].begin(); it != Poly[n].end(); it++) {
					int maxx = 0, maxy = 0;
					for (sit it1 = (*it).begin(); it1 != (*it).end(); it1++) {
						maxx = max(it1->x, maxx);
						maxy = max(it1->y, maxy);
					}
					if (min(maxx, maxy) < min(h, w) && max(maxx, maxy) < max(h, w)) cnt++;
				}
				ans[n][w][h] = cnt;
			}

}
int main()
{
	generate();
	int n, h, w;
	while (scanf("%d%d%d", &n, &w, &h) == 3)
		cout << (n == 1 ? 1 : ans[n][w][h]) << endl;

}

猜你喜欢

转载自blog.csdn.net/qq_41776911/article/details/82469468