【DFS】【打表】Lattice Animals
[ZOJ2669]Lattice Animals
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; }