UVa 1602 Lattice Animals
阿新 • • 發佈:2019-02-01
Lattice animal is a set of connected sites on a lattice. Lattice animals on a square lattice are especially popular
subject of study and are also known as polyominoes. Polyomino is usually represented as a set of sidewise connected
squares. Polyomino with n squares is called n-polyomino.
In this problem you are to find a number of distinct freen-polyominoes
that fit into rectangle w×h.
Free polyominoes can be rotated and flipped over, so that their rotations and mirror images are considered to be the same. For example, there are 5 different pentominoes (5-polyominoes) that fit into 2×4 rectangle
and 3 different octominoes (8-polyominoes) that fit into 3×3 rectangle.
w×h.
列舉所有的n連塊,難點在於如何列舉,沒有想出來,後來參考https://github.com/aoapc-book/aoapc-bac2nd/blob/master/ch7/UVa1602.cpp,自己實現了一遍。
Input
The input file contains several test cases, one per line. This line consists of 3 integer numbers n, w, and h (1n10, 1w, hn). For each one of the test cases, write to the output file a single line with a integer number -- the number of distinct free n-polyominoes that fit into rectangle5 1 4 5 2 4 5 3 4 5 5 5 8 3 3
0 5 11 12 3
#include <cstdio>
#include <set>
#include <algorithm>
using namespace std;
#define maxn 10
// 代表一個網格節點
typedef struct cell
{
int x, y; //網格節點的座標
// 建構函式
cell(int x, int y)
{
this->x = x;
this->y = y;
}
bool operator < (const struct cell& a) const
{
return x < a.x || (x == a.x && y < a.y);
}
}cell;
// 一個Polyomino就是一堆cell的集合
typedef set<cell> poly;
// poly_set[i]代表有i個cell的poly集合
set<poly> poly_set[maxn+1];
// answer[n][w][h]的答案
int answer[maxn+1][maxn+1][maxn+1];
void gen_poly();
void check_poly(const poly& this_p, cell& this_c);
poly normalize(poly& p);
poly rotate(poly& p);
poly flip(poly& p);
int main()
{
// 生成所有poly
gen_poly();
// printf("here\n");
int n, w, h;
while(scanf("%d %d %d", &n, &w, &h) == 3)
{
printf("%d\n", answer[n][w][h]);
}
return 0;
}
int dic_x[4] = {-1,0,1,0};
int dic_y[4] = {0,1,0,-1};
// 生成所有poly
void gen_poly()
{
for(int i = 1; i <= maxn; i++)
poly_set[i] = set<poly>();
// 先生成有1個cell的poly
poly p1;
p1.insert(cell(0,0));
poly_set[1].insert(p1);
// 分別根據有i-1個cell的poly集合來生成有i個cell的poly集合
for(int i = 2; i <= maxn; i++)
{
// 對每個poly中的每個cell嘗試在不同的四個方向增加一個cell
for(set<poly>::iterator p = poly_set[i-1].begin(); p != poly_set[i-1].end(); p++)
{
for(poly::const_iterator q = p->begin(); q != p->end(); q++)
{
for(int j = 0; j < 4; j++)
{
cell new_c(q->x+dic_x[j], q->y+dic_y[j]);
// cell new_c;
if(p->find(new_c) == p->end())
{
// 檢查形成的這個poly是否存在,如果不存在就加入
check_poly(*p, new_c);
}
}
}
}
}
// 對所有n,w,h生成答案
for(int i = 1; i <= maxn; i++)
{
for(int w = 1; w <= i; w++)
{
for(int h = 1; h <= i; h++)
{
int count = 0;
for(set<poly>::iterator p = poly_set[i].begin(); p != poly_set[i].end(); p++)
{
int max_x = p->begin()->x, max_y = p->begin()->y;
for(poly::iterator q = p->begin(); q != p->end(); q++)
{
if(max_x < q->x)
max_x = q->x;
if(max_y < q->y)
max_y = q->y;
}
if(min(max_x, max_y) < min(w, h) && max(max_x, max_y) < max(w, h))
{
count++;
}
}
/* if(count != 0)
printf("answer[%d][%d][%d] = %d\n", i, w, h, count);
*/ answer[i][w][h] = count;
}
}
}
}
// 檢查形成的這個poly加上這個cell是否存在,如果不存在就加入
void check_poly(const poly& this_p, cell& this_c)
{
poly p = this_p;
p.insert(this_c);
// 規範化到最小點為(0,0)
p = normalize(p);
int n = p.size();
// 檢查旋轉的8個方向是否存在,如果不存在就加入到poly集合
for(int i = 0; i < 4; i++)
{
if(poly_set[n].find(p) != poly_set[n].end())
return;
// 對該poly向右旋轉90度
p = rotate(p);
}
// 將該poly向下反轉180度
p = flip(p);
for(int i = 0; i < 4; i++)
{
if(poly_set[n].find(p) != poly_set[n].end())
return;
// 對該poly向右旋轉90度
p = rotate(p);
}
poly_set[n].insert(p);
}
// 規範化到最小點為(0,0)
poly normalize(poly& p)
{
poly this_p;
int min_x = p.begin()->x, min_y = p.begin()->y;
for(poly::iterator q = p.begin(); q != p.end(); q++)
{
if(q->x < min_x)
min_x = q->x;
if(q->y < min_y)
min_y = q->y;
}
for(poly::iterator q = p.begin(); q != p.end(); q++)
{
this_p.insert(cell(q->x-min_x,q->y-min_y));
}
return this_p;
}
// 對該poly向右旋轉90度
poly rotate(poly& p)
{
poly this_p;
for(poly::iterator q = p.begin(); q != p.end(); q++)
{
this_p.insert(cell(q->y,-q->x));
}
return normalize(this_p);
}
// 將該poly向下反轉180度
poly flip(poly& p)
{
poly this_p;
for(poly::iterator q = p.begin(); q != p.end(); q++)
{
this_p.insert(cell(q->x,-q->y));
}
return normalize(this_p);
}
列舉所有的n連塊,難點在於如何列舉,沒有想出來,後來參考https://github.com/aoapc-book/aoapc-bac2nd/blob/master/ch7/UVa1602.cpp,自己實現了一遍。
難點:
1.以每個格子來擴充套件。先列舉1連塊,在對1連塊的每個格子的4個方向進行擴充套件,列舉2連塊,依次類推。
2.將n連塊表示成n個格子的集合,將所有的n連塊又表示成集合,判重任務交給set.
3.判重時要將n連塊進行8個方向的旋轉,並且每個n連塊需要規範化(左下角的格子在(0,0)).
4.得到n連塊後判斷是否能放進w*h的網格中,由於n連塊已經規範化,得到n連塊的格子最大x,y座標,即能盛下該n連塊的長和寬。