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.

Input

The input file contains several test cases, one per line. This line consists of 3 integer numbers nw, and h ( 1n10, 1whn).

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连块的长和宽。
#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);
}

ACM题目————网格动物的更多相关文章

  1. ACM题目————中缀表达式转后缀

    题目描述 我们熟悉的表达式如a+b.a+b*(c+d)等都属于中缀表达式.中缀表达式就是(对于双目运算符来说)操作符在两个操作数中间:num1 operand num2.同理,后缀表达式就是操作符在两 ...

  2. ACM题目————食物链

    题目描述 Description 动物王国中有三类动物 A,B,C,这三类动物的食物链构成了有趣的环形.A吃B,B吃C,C吃A. 现有N个动物,以1-N编号.每个动物都是A,B,C中的一种,但是我们并 ...

  3. HDU ACM 题目分类

    模拟题, 枚举1002 1004 1013 1015 1017 1020 1022 1029 1031 1033 1034 1035 1036 1037 1039 1042 1047 1048 104 ...

  4. ACM题目推荐(刘汝佳书上出现的一些题目)[非原创]

    原地址:http://blog.csdn.net/hncqp/article/details/1758337 推荐一些题目,希望对参与ICPC竞赛的同学有所帮助. POJ上一些题目在http://16 ...

  5. 有一种acm题目叫做,奇葩!

    本文全然没有技术含量,纯粹是娱乐. 我事实上想写点东西.可是近期好像做计算几何做得太多了,一种想说说不出东西的感觉,唯有写一下一些奇葩的题目了. HDU3337:Guess the number pi ...

  6. ACM题目————STL练习之求次数

    题目地址:http://acm.nyist.net/JudgeOnline/problem.php?pid=1112 描述 题意很简单,给一个数n 以及一个字符串str,区间[i,i+n-1] 为一个 ...

  7. UVa 1602 网格动物(回溯)

    https://vjudge.net/problem/UVA-1602 题意:计算n连通块不同形态的个数. 思路: 实在是不知道该怎么做好,感觉判重实在是太麻烦了. 判重就是判断所有格子位置是否都相同 ...

  8. 网格动物UVA1602

    题目大意 输入n,w,h(1<=n<=10,1<=w,h<=n).求能放在w*h网格里的不同的n连块的个数(平移,旋转,翻转算一种) 首先,方法上有两个,一是打表,dfs构造连 ...

  9. ACM题目————zoj问题

    题目1006:ZOJ问题 时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:20322 解决:3560 题目描述: 对给定的字符串(只包含'z','o','j'三种字符),判断他是否能AC. ...

随机推荐

  1. defer 要放在return之前

    虽然defer可以在函数退出的时候执行,但是也要把它放在return之前,否则不会调用到. 错误的示范: res, err := Resource.open() if err != nil { ret ...

  2. iOS UITableView的分割线短15像素,移动到最左边的方法(iOS8)

    有好几个朋友问我ios 分割线端了一些 如何解决,于是我就写一篇博客吧.为什么我说是少了15像素呢?首先我们拖拽一个默认的tableview 控件! 看下xcode5 面板的inspector(检查器 ...

  3. linux:档案与目录管理

    几个常见的目录处理命令: cd(change directory):变更目录 pwd(print working directory):显示当前目录[目录为连结档,则只显示连结档的路径]([-P]不以 ...

  4. window.cookie

    本地测试cookie用火狐来测试 首先cookie是document上的一个属性. 先弹出一个cookie alert(document.cookie); //弹出是空的 设置cookie,格式是有一 ...

  5. Java中几种日志方案

    .本文记录Java中几种常用的日志解决方案 0x01 Log4j .这应该是一个比较老牌的日志方案了,配置也比较简单,步骤如下 1)添加对应依赖,比如 Gradle 中 dependencies { ...

  6. FAQ: c++ 函数名后添加 const void function1(int &id) const

    说明这个函数不能修改这个类的成员变量!只能操作自己的参数和内部的范围变量! 括号内的&id,&表示这个变量和C# in和out是一样的,算是一个reference,可以更改值,要想不更 ...

  7. csuoj 1120: 病毒

    http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1120 1120: 病毒 Time Limit: 3 Sec  Memory Limit: 128 ...

  8. Java基础(43):Java中的Object类与其方法(转)

    Object类 java.lang.Object java.lang包在使用的时候无需显示导入,编译时由编译器自动导入. Object类是类层次结构的根,Java中所有的类从根本上都继承自这个类. O ...

  9. struts不同session范围添加、访问属性

    第01步:编写bean类 package com.self.bean; import java.util.Date; public class User { private Date birthday ...

  10. Mysql 修改字段长度、修改列名、新增列

    alter table 表名 modify column 字段名 类型; 例如 数据库中user表 name字段是varchar(30) 可以用 ) ; --修改字段长度 )--修改表列名 ); -- ...