[ZOJ2669]Lattice Animals


Time Limit: 5 Seconds      Memory Limit: 32768 KB

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 polyminoes. Polymino is usually represented as a set of sidewise connected squares. Polymino with n squares is called n-polymino.

In this problem you are to find a number of distinct free n-polyminoes that fit into rectangle w * h. Free polyminoes 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 pentaminoes (5-polyminoes) that fit into 2 * 4 rectangle and 3 different octominoes (8-polyminoes) that fit into 3 * 3 rectangle.

Input

There are several test cases in the input. Each case consists of a single line with 3 integer numbers n, w, and h (n ≤ 10, 1 ≤ w, h ≤ n).

Output

Write to the output file a single integer number --- the number of distinct free n-polyminoes 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


Source: Northeastern Europe 2004

这是NEERC2004的题目,好像有两个人A……

ZOJ的测评机跑的貌似比较快,交其它OJ全都是TLE,网上部分标程也是。我叫UVA上RE不知道为何……

题目大意就是生成N连块,N<=10,然后有一堆询问,每次询问N连块中,有W*H的棋盘可以放下多少个N连块。

先将N连块求出来,然后再将每个N连块的贡献记入答案。时间限制虽然是5秒,但是应该要掌握预处理在2秒以内才可以(反正2.1秒的我T了)

ZOJ上690MS,orz 0ms秒过的dalao……

众多标程都是与刘汝佳一样用的Set,跑起来貌似能比一样思想的程序快1秒(亲测)

试题分析:大暴力:直接枚举下一个块可以放在哪里,拓展即可。

         很容易想到一个优化:用N-1连块的答案来更新N连块的答案(显而易见不会漏掉答案)

         当然,加上旋转翻转等一类Set的简易操作,貌似就可以了。

         但我并没有写Set(不会很无奈啊,从来不用),然后就引来了众多莫名其妙的优化。

         Part1(优化3秒左右):Hash

            Hash优化是最先想到的一类优化,两个块一样必定Hash值相等,因此搞了两个Hash,其实一个Hash足矣。实测时间差不多。

         Part2(Hash优化后优化200ms左右):W,H

            注意到从N-1连块到N连块的长度或者高度最多其中一项+1.

            这时我们就可以只翻转+旋转W,H这一块,其余并不用翻转,Hash、判断相等也只用这一块就好了。

            现在就自然而然就多了一个剪枝:当两个块的W,H其一不等时,这两个块一定不相等。

         Part3(上两项优化完后优化1s左右):Del

            Del是去0操作,旨在去掉上面和左边的0,保证图形在10*10的棋盘的左上角。

               发现Del多了,删去后就优化1s左右。

      还有一些优化想出来了但没有用,可能不会优化太多:

         将每个N连块每行每列的有几个块都求出来,然后比完Hash与W,H后比这两个信息是否一样,不一样则退出。

         但这并不能完全确定一个联通块,比如:

         110  101

         111  111

         001  010

         这样列是:2 2 2      2 2 2

           行是:2 3 1      2 3 1

         一开始就是写完了这个发现不行,然后删了想了想又写了一天上面的东西。。。

     个人认为题还是挺不错的,值得一做,但要做好心理准备……

代码:

#include<iostream>
#include<cstring>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std; #define LL long long inline int read(){
int x=0,f=1;char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
for(;isdigit(c);c=getchar()) x=x*10+c-'0';
return x*f;
}
const int INF=9999999;
const int MAXN=100000;
const int T=10;
int N,M,K;
int Maxd;
bool vis[21][21];
bool vist[21][21];
int W1,H1;
int dis[5][2]={{0,1},{1,0},{0,-1},{-1,0}};
bool txt[21][21]; struct data{
int w,h;
bool mp[21][21];
int dit[21];long long dit2[21];
long long Hash1,Hash2;
};
vector<data> vec[21]; void del0(){
int move=INF;
for(int i=0;i<T;i++){
int cnt=-1;
while(!txt[i][cnt]) cnt++;
move=min(cnt-1,move);
}
if(move>=0){
for(int i=0;i<T;i++){
for(int j=move+1;j<T;j++){
txt[i][j-move-1]=txt[i][j];
txt[i][j]=0;
}
}
}
move=INF;
for(int j=0;j<T;j++){
int cnt=-1;
while(!txt[cnt][j]) cnt++;
move=min(cnt-1,move);
}
if(move>=0){
for(int i=move+1;i<T;i++){
for(int j=0;j<T;j++){
txt[i-move-1][j]=txt[i][j];
txt[i][j]=0;
}
}
}
return ;
}
bool vis2[21][21];
int ans[21][21][21];
int W,H;
int dig[21];long long dig2[21];
void rota(){
memset(vis2,0,sizeof(vis));
for(int i=0;i<H1;i++)
for(int j=0;j<W1;j++) vis2[i][j]=txt[i][j];
memset(txt,0,sizeof(txt));
for(int i=0;i<H1;i++){
for(int j=0;j<W1;j++)
txt[j][i]=vis2[i][W1-j-1];
}
swap(W1,H1);
return ;
}
long long Has;
bool judge(){
int t=vec[Maxd].size();
if(!t) return true;
for(int i=0;i<5;i++){
if(i) rota();
Has=0;
for(int a=0;a<H1;a++){
long long cnt=0;
for(int b=0;b<W1;b++){
if(txt[a][b]) cnt+=((1<<b)*a);
}
Has+=cnt;
dig[a]=cnt;
}
long long Has2=0;
for(int a=0;a<H1;a++){
long long cnt=0;
for(int b=0;b<W1;b++){
if(txt[a][b]) cnt+=(1<<(a*b)+a*b)%999997;
}
dig2[a]=cnt;
Has2+=cnt;
Has2%=999999997;
}
for(int j=0;j<t;j++){
if(Has!=vec[Maxd][j].Hash1) continue;
if(Has2!=vec[Maxd][j].Hash2) continue;
if(W1!=vec[Maxd][j].w||H1!=vec[Maxd][j].h) continue;
bool flag=true;
for(int a=0;a<H1;a++)
if(dig[a]!=vec[Maxd][j].dit[a]) {
flag=false;break;
}
if(!flag) continue;
for(int a=0;a<H1;a++)
if(dig2[a]!=vec[Maxd][j].dit2[a]) {
flag=false;break;
}
if(!flag) continue;
for(int a=0;a<H1;a++){
for(int b=0;b<W1;b++){
if(vec[Maxd][j].mp[a][b]!=txt[a][b]){
flag=false;
break;
}
}
if(!flag) break;
}
if(flag) return false;
}
}
return true;
}
void pushin(){
data tk;
long long Has2=0;
for(int i=0;i<T;i++)
for(int j=0;j<T;j++)
tk.mp[i][j]=txt[i][j];
for(int a=0;a<H1;a++){
long long cnt=0;
for(int b=0;b<W1;b++){
if(txt[a][b]) cnt+=((1<<b)*a);
}
tk.dit[a]=cnt;
Has2+=cnt;
}
tk.Hash1=Has2;
Has2=0;
for(int a=0;a<H1;a++){
long long cnt=0;
for(int b=0;b<W1;b++){
if(txt[a][b]) cnt+=(1<<(a*b)+a*b)%999997;
}
tk.dit2[a]=cnt;
Has2+=cnt;
Has2%=999999997;
}
tk.Hash2=Has2;
tk.w=W1;
tk.h=H1;
vec[Maxd].push_back(tk);
return ;
}
bool ti[21][21]; void GA(int d){
for(int a=1;a<=H+1;a++)
for(int b=1;b<=W+1;b++){
if(!vis[a][b]) continue;
for(int k=0;k<4;k++){
int xx=dis[k][0]+a;
int yy=dis[k][1]+b;
if(xx>=T||yy>=T) continue;
if(ti[xx][yy]) continue;
if(vis[xx][yy]) continue;
ti[xx][yy]=true;
vis[xx][yy]=1;
for(int i=0;i<T;i++)
for(int j=0;j<T;j++) txt[i][j]=vis[i][j];
del0();
int h=0;
for(int i=0;i<T;i++){
int p=T-1;
while(!txt[i][p]) p--;
h=max(h,p+1);
}
W1=h;
int w=0;
for(int j=0;j<T;j++){
int p=T-1;
while(!txt[p][j]) p--;
w=max(w,p+1);
}
H1=w;
vis[xx][yy]=0;
if(!judge()) continue;
rota();
for(int i=0;i<H1/2;i++)
for(int j=0;j<W1;j++)
swap(txt[i][j],txt[H1-i-1][j]);
if(!judge()) continue;
pushin();
}
}
return ;
}
void pre(){
txt[0][0]=1;
Maxd=1;
pushin();
txt[0][0]=0;
for(Maxd=2;Maxd<=T;Maxd++) {
for(int i=0;i<vec[Maxd-1].size();i++){
W=vec[Maxd-1][i].w;H=vec[Maxd-1][i].h;
memset(vis,0,sizeof(vis));
for(int j=0;j<T;j++)
for(int k=0;k<T;k++)
vis[j][k]=vec[Maxd-1][i].mp[j][k];
for(int k=T-1;k>0;k--)
for(int j=0;j<T;j++)
vis[k][j]=vis[k-1][j],vis[k-1][j]=0;
for(int k=0;k<T;k++)
for(int j=T-1;j>0;j--)
vis[k][j]=vis[k][j-1],vis[k][j-1]=0;
memset(ti,0,sizeof(ti));
GA(1);
}
for(int i=0;i<vec[Maxd].size();i++){
for(int j=1;j<=10;j++)
for(int k=1;k<=10;k++){
if((vec[Maxd][i].w<=k&&vec[Maxd][i].h<=j)||(vec[Maxd][i].w<=j&&vec[Maxd][i].h<=k)) ans[Maxd][j][k]++;
}
}
}
} int main(){
pre();
while(scanf("%d%d%d",&N,&M,&K)!=EOF){
if(N==1) puts("1");
else printf("%d\n",ans[N][M][K]);
}
return 0;
}

【DFS】【打表】Lattice Animals的更多相关文章

  1. DFS+打表

    N皇后问题 Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Status ...

  2. HDU 2586 How far away(dfs+邻接表)

    How far away [题目链接]How far away [题目类型]dfs+邻接表 &题意: 题目大意:一个村子里有n个房子,这n个房子用n-1条路连接起来,接下了有m次询问,每次询问 ...

  3. HDU 2563 统计问题 (DFS + 打表)

    统计问题 Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submi ...

  4. UVA-1602 Lattice Animals 搜索问题(打表+set)

    题目链接 https://vjudge.net/problem/UVA-1602 紫书的一道例题,跟之前的很多题目有很多不同. 本题不像是一般的dfs或bfs这样的搜索套路,而是另一种枚举思路. 题意 ...

  5. ACM: HDU 2563 统计问题-DFS+打表

    HDU 2563 统计问题 Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u HDU 2 ...

  6. codeforces 285 D. Permutation Sum 状压 dfs打表

    题意: 如果有2个排列a,b,定义序列c为: c[i] = (a[i] + b[i] - 2) % n + 1 但是,明显c不一定是一个排列 现在,给出排列的长度n (1 <= n <= ...

  7. hdu 2510 符号三角形 (DFS+打表)

    符号三角形 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submi ...

  8. hdu2510-符号三角形(dfs+打表)

    n只有24 可以写个暴力搜索,然后打表,不然这个很难通过剪枝直接优化到1s以内. #include<bits/stdc++.h> #define inf 0x3f3f3f3f ; usin ...

  9. hdu 1848 sg——dfs&&打表双实现

    Fibonacci again and again Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Jav ...

随机推荐

  1. ios的app,有新版本时必须先更新。

    现在没时间整理,先把代码贴出来,以后再做详细的思路整理. 1 在AppController.mm的didFinishLaunchingWithOptions方法里面获取本地应用版本信息,保存起来. / ...

  2. 所有和Java中代理有关的知识点都在这了。

    对于每一个Java开发来说,代理这个词或多或少都会听说过.你可能听到过的有代理模式.动态代理.反向代理等.那么,到底什么是代理,这么多代理又有什么区别呢.本文就来简要分析一下. 代理技术,其实不只是J ...

  3. C#读取txt文件时中文乱码

    解决办法 使用GB2312中文字符集 StreamReader reader = new StreamReader(txtUrl, Encoding.GetEncoding("gb2312& ...

  4. 网络协议之HTTP协议

    HTTP协议详解(真的很经典) 转自:http://blog.csdn.net/gueter/archive/2007/03/08/1524447.aspx Author :Jeffrey 引言 HT ...

  5. Python阶段复习 - part 3 - Python函数

    利用函数打印9*9乘法表 def cheng(num): for i in range(1,num+1): for j in range(1,i+1): print('{0} * {1} = {2}' ...

  6. gcc中的内嵌汇编语言(Intel i386平台)

    [转]http://bbs.chinaunix.net/thread-2149855-1-1.html 一.声明  虽然Linux的核心代码大部分是用C语言编写的,但是不可避免的其中还是有一部分是用汇 ...

  7. 【2017 Multi-University Training Contest - Team 1】小结

    啊人生第一次打多校被虐 紧随yql的脚步做题. 1001: 可以发现我们平时表示的数都是$x*log_{10}{10}$,所以类似于做一个换底公式就可以了. -1是一个烟雾弹,因为小学生都知道2^n不 ...

  8. [hadoop][会装]zookeeper安装

    1.简介 分布式场景下的各个进程间的协调运作离不开zookeeper, zookeeper已经是大数据领域提供分布式协调服务的事实标准. 本文只介绍zookeeper的安装方法. 2. 节点规划如下: ...

  9. JavaScript中对象的属性类型

    JavaScript中,对象的属性有两种:数据属性和访问器属性. 数据属性 特性: 数据属性包括一个数据值的位置.在这个位置可以读取和写入值.数据属性有4个特性. [[configurable]]:可 ...

  10. JWT认证不通过导致不能访问视图的解决方案

    在做商城项目的购物车模块时,发现了一个问题. 需求:当用户登录时,添加商品到购物车的数据保存在redis.当用户未登录时,添加商品到购物车的数据保存在cookies.两个功能都写在一个视图里面.以JW ...