UVA 1602 Lattice Animals

https://vjudge.net/problem/UVA-1602

 

题意:w*h网格里放n连块,问有多少种放法

翻转、旋转90°、平移之后相同的算一种

 

推荐题解:

http://blog.csdn.net/qq_29169749/article/details/51420013

 

解决本题的三个问题:

1、状态的有效表示

2、状态的搜索

3、状态的判重

 

1、状态表示:set套set

定义结构体类型Cell 表示每一个格子的坐标

set<Cell>polyomino 表示一个合法的连通块 坐标 集合

set<polyomino>sp[i]  表示所有的i连块集合

这样用set里带的count() 可以方便的判重

 

2、每一个n连块都可以有一个n-1连块增加一个而来

 

3、

平移:

将连通块标准化,即连通块里坐标最小的格子(minx,miny)映射到(0,0)上去,

然后连通块整体沿向量(minx,miny)方向平移

称之为标准化

标准化之后的连通块相同,则他们可以通过平移操作相同

旋转:

现将连通块标准化

然后每次旋转90°,即坐标由(x,y)变为(y,-x)

然后再标准化

翻转:

先将连通块标准化

然后沿x轴翻转,即坐标由(x,y)变为 (x,-y)

然后再标准化

 

翻转时只需沿x轴翻转

因为沿y轴翻转可以看做 先沿x轴翻转,再旋转2次90°

对于每一种翻转、旋转、翻转之后再旋转、旋转之后再翻转

均可以有旋转和翻转的组合完成

 

所以判重的时候,先判平移

然后 旋转4次90°

然后沿x轴翻转,再旋转4次90°

 

#include<set>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>

using namespace std;

int ans[11][11][11];

struct  Cell
{
    int x,y;
    Cell(int x=0,int y=0):x(x),y(y) { }
    bool operator < (const Cell & rhs) const
    {
        if(x!=rhs.x) return x<rhs.x;
        return y<rhs.y; 
    }
};
typedef set<Cell> polyomino;
set<polyomino> sp[11];

const int dir_x[]={-1,1,0,0};
const int dir_y[]={0,0,-1,1};

inline polyomino normalize(const polyomino &p)
{
    int minx=p.begin()->x,miny=p.begin()->y;
    for(polyomino :: const_iterator it=p.begin();it!=p.end();it++)
    {
        minx=min(minx,it->x);
        miny=min(miny,it->y);
    }
    
    polyomino tmp;
    for(polyomino :: const_iterator it=p.begin();it!=p.end();it++)
    {
        int x=it->x,y=it->y;
        tmp.insert(Cell(x-minx,y-miny));
    }
    return tmp;
}

inline polyomino rotation(const polyomino &p)
{
    polyomino tmp;
    for(polyomino :: const_iterator it=p.begin();it!=p.end();it++)
    {
        int x=it->x,y=it->y;
        tmp.insert(Cell(y,-x));
    }
    return normalize(tmp);
}

inline polyomino flip_x(const polyomino &p)
{
    polyomino tmp;
    for(polyomino :: const_iterator it=p.begin();it!=p.end();it++)
    {
        int x=it->x,y=it->y;
        tmp.insert(Cell(x,-y));
    }
    return normalize(tmp);
 } 

void set_poly(const polyomino & p,const Cell &c)
{
    polyomino tmp=p;
    tmp.insert(c);
    tmp=normalize(tmp);
    
    int n=tmp.size();
    for(int i=0;i<4;i++)
    {
        if(sp[n].count(tmp)) return;
        tmp=rotation(tmp);
    } 
    
    tmp=flip_x(tmp);
    for(int i=0;i<4;i++)
    {
        if(sp[n].count(tmp)) return;
        tmp=rotation(tmp);
    }
    
    sp[n].insert(tmp);
}

void make_Ans_List()
{
    polyomino cur;
    cur.insert(Cell(0,0));
    sp[1].insert(cur);
    
    for(int n=1;n<=10;n++)
        for(set<polyomino>::iterator it=sp[n-1].begin();it!=sp[n-1].end();it++)
            for(polyomino ::const_iterator cit=(*it).begin();cit!=(*it).end();cit++)
                for(int dir=0;dir<4;dir++)
                {
                    Cell newc(cit->x+dir_x[dir],cit->y+dir_y[dir]);
                    if((it->count(newc))==0) set_poly(*it,newc);
                }
    
    for(int n=1;n<=10;n++)
        for(int w=1;w<=10;w++)
            for(int h=1;h<=10;h++)
            {
                int cnt=0;
                for(set<polyomino>::iterator it=sp[n].begin();it!=sp[n].end();it++)
                {
                    int maxx=0,maxy=0;
                    for(polyomino :: const_iterator c=(*it).begin();c!=(*it).end();c++)
                    {
                        maxx=max(maxx,c->x);
                        maxy=max(maxy,c->y);
                    }
                    if(min(maxx,maxy)<min(w,h) && max(maxx,maxy)<max(w,h)) cnt++;
                }
                ans[n][w][h]=cnt;
            }
 } 

int main()
{
    make_Ans_List();
    int n,w,h;
    while(scanf("%d%d%d",&n,&w,&h)!=EOF)
    {
        if(n>w*h) printf("0\n");
        else printf("%d\n",ans[n][w][h]);
    }
}

 

posted @ 2017-10-14 21:38  TRTTG  阅读(393)  评论(0编辑  收藏  举报