题意:输入n,w,h (1≤n≤10,1≤w,h≤n) ,求能放在 w∗h 网格里的不同n连块的个数(注意,平移、旋转、翻转后相同的算作同一种)。例如, 2∗4 的5连块有5种(第一行),而 3∗3 里的8连块有以下3种(第二行),如图所示。(本段摘自《算法竞赛入门经典(第2版)》
分析:
从1开始向后递推枚举网格,因为n连块总是由n - 1连块得来的。判重的时候要注意翻转和旋转最多可能有8种形态,都要判断。
代码:
#include <iostream>
#include <algorithm>
#include <fstream>
#include <cstring>
#include <set>
using namespace std;
const int maxn = 10 + 5;
const int dx[] = {-1, 1, 0, 0}, dy[] = {0, 0, -1, 1};
struct Cell
{
int x, y;
Cell(int x = 0, int y = 0) : x(x), y(y) {}
bool operator < (const Cell& right) const
{
return (x == right.x) ? (y < right.y) : (x < right.x);
}
};
typedef set< Cell > Polyomino;
Polyomino normalize(const Polyomino &p)
{
int minX = p.begin()->x, minY = p.begin()->y;
for (Polyomino::const_iterator cit = p.begin(); cit != p.end(); ++cit)
{
minX = min(minX, cit->x);
minY = min(minY, cit->y);
}
Polyomino p2;
for (Polyomino::const_iterator cit = p.begin(); cit != p.end(); ++cit)
p2.insert(Cell(cit->x - minX, cit->y - minY));
return p2;
}
Polyomino rotate(const Polyomino &p)
{
Polyomino p2;
for (Polyomino::const_iterator cit = p.begin(); cit != p.end(); ++cit)
p2.insert(Cell(cit->y, -cit->x));
return normalize(p2);
}
Polyomino flip(const Polyomino &p)
{
Polyomino p2;
for (Polyomino::const_iterator cit = p.begin(); cit != p.end(); ++cit)
p2.insert(Cell(cit->x, -cit->y));
return normalize(p2);
}
set< Polyomino > poly[maxn];
int ans[maxn][maxn][maxn];
int n, w, h;
void try_add(const Polyomino& p0, const Cell& c)
{
Polyomino p = p0;
p.insert(c);
p = normalize(p);
int n = p.size();
for (int i = 0; i < 4; ++i)
{
if (poly[n].count(p) != 0)
return;
p = rotate(p);
}
p = flip(p);
for (int i = 0; i < 4; ++i)
{
if (poly[n].count(p) != 0)
return;
p = rotate(p);
}
poly[n].insert(p);
}
void solve()
{
Polyomino p;
p.insert(Cell(0, 0));
poly[1].insert(p);
for (int n = 2; n <= 10; ++n)
{
for (set< Polyomino >::iterator it = poly[n - 1].begin(); it != poly[n - 1].end(); ++it)
{
for (Polyomino::const_iterator cit = (*it).begin(); cit != (*it).end(); ++cit)
{
for (int i = 0; i < 4; ++i)
{
Cell cell(cit->x + dx[i], cit->y + dy[i]);
if (it->count(cell) == 0)
try_add(*it, cell);
}
}
}
}
for (int n = 1; n <= 10; ++n)
for (int w = 1; w <= 10; ++w)
for (int h = 1; h <= 10; ++h)
{
int cnt = 0;
for (set< Polyomino >::iterator it = poly[n].begin(); it != poly[n].end(); ++it)
{
int maxX = 0, maxY = 0;
for (Polyomino::const_iterator cit = (*it).begin(); cit != (*it).end(); ++cit)
{
maxX = max(maxX, cit->x);
maxY = max(maxY, cit->y);
}
if (min(maxX, maxY) < min(h, w) && max(maxX, maxY) < max(h, w))
++cnt;
}
ans[n][w][h] = cnt;
}
}
int main()
{
solve();
while (~scanf("%d%d%d", &n, &w, &h))
printf("%d\n", ans[n][w][h]);
return 0;
}