zoukankan      html  css  js  c++  java
  • 【DFS】【打表】Lattice Animals

    [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
    ",ans[N][M][K]);
    	}
    	return 0;
    }

     

  • 相关阅读:
    11.8-ros-navigation解析
    8.14-rqt_common_pluggins 详解
    8.1-roscomm详解
    8.15-ros-bag使用
    7.26-rosbridge-suit 解读
    7.26-roscpp_overview详解
    7.26-ROS其他有价值模块
    java dbutils查询数据库时无法给部分字段赋值原因
    java_获取多个文件夹下所有.java源码的总行数
    正则表达式-1-初识正则表达式
  • 原文地址:https://www.cnblogs.com/wxjor/p/7414163.html
Copyright © 2011-2022 走看看