ACM题目————网格动物

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 free n-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.

\epsfbox{p3224.eps}

Input 

The input file contains several test cases, one per line. This line consists of 3 integer numbers nw, and h ( 1$ \le$n$ \le$101$ \le$wh$ \le$n).

Output 

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 rectangle w×h.

Sample Input 

5 1 4
5 2 4
5 3 4
5 5 5
8 3 3

Sample Output 

0
5
11
12
3

输入n,w,h (1<=n<=10,1<=w,h<=n),求能放在w*h网格里的不同的n连块的个数(注意,平移,旋转,翻转后相同的算作同一种)。例如,2*4里的5连块有5种(第一行),而3*3里的8连块有以下3种(第二行)。

 

 

难点:

 

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连块的长和宽。

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
#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);
}

 

posted @   Asimple  阅读(658)  评论(0编辑  收藏  举报
编辑推荐:
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示