参考博客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;
}