zoukankan      html  css  js  c++  java
  • 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
    ");
            else printf("%d
    ",ans[n][w][h]);
        }
    }
  • 相关阅读:
    js 函数声明和函数表达式的区别
    使用dom4j工具包对xml文件解析
    xml的schema约束
    xml的DTD约束
    C3P0连接池工具类使用
    jdbc连接警告不安全
    java的unity单元测试
    BootStrap容器介绍
    validate插件实现表单效验(二)
    validate插件实现表单效验(一)
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/7668659.html
Copyright © 2011-2022 走看看