Lattice Animals UVa1602

题意:由n个方格可以组成不同形状的连通块,经过平移、旋转k*90°、翻转操作能够重合的两个连通块视为同一种。给定整数n, w, h, 求能够放进w*h的矩形内的n连通块种数。
分析:
1.数据结构:定义结构体point{int x,y}表示方格;类lattice{set<point>}表示连通块;set<lattice>ans[i]表示不同i连通块构成的集合。

2.连通块平移、旋转、翻转变换:平移即lattice中的每个point加上(dx,dy);旋转90°即(x,y)->(y,-x); 翻转即(x,y)->(x,-y)
3.判重:即判断一个连通块是否在一个连通块的集合中。对它进行不变、三次旋转、翻转、三次旋转,得到共八个状态。对每个状态进行“标准化平移”:即平移使得连通块最小的x为0,最小的y为0。

4.从i连通块递推到i+1连通块:分别对每个i连通块的每个point向四周四个点扩展一次,对于扩展后符合与之前的不重复、w*h装得下的条件的i连通块,是新得到的,放进ans[i]中。
代码:
//Lattice Animals
#include<iostream>
#include<set>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int INF=-0x7FFFFFFF, SUP=0x7FFFFFFF;
class point
{
public:
    int x, y;
    point() {}
    point(int ix, int iy): x(ix), y(iy) {}
    bool operator < (const point& p) const
    {
        if (x==p.x) return y<p.y;
        return x<p.x;
    }
};
class lattice
{
public:
    set<point> pts;
    int maxx, minx, maxy, miny;
    lattice() {}
    lattice(point& p): maxx(p.x), minx(p.x), maxy(p.y),  miny(p.y) {
        pts.insert(p);
    }
    lattice(const point p): maxx(p.x), minx(p.x), maxy(p.y),  miny(p.y) {
        pts.insert(p);
    }
    void input(point& p) {
        pts.insert(p);
        maxx=max(p.x, maxx);
        minx=min(p.x, minx);
        maxy=max(p.y, maxy);
        miny=min(p.y, miny);
    }
    void input(const point p) {
        pts.insert(p);
        maxx=max(p.x, maxx);
        minx=min(p.x, minx);
        maxy=max(p.y, maxy);
        miny=min(p.y, miny);
    }
};
set<lattice> ans[11];
void stdMove(lattice& l)
{
    l.minx=SUP; l.miny=SUP; l.maxx=INF; l.maxy=INF;
    for (set<point>::iterator it=l.pts.begin(); it!=l.pts.end(); ++it) {
        if ((*it).x<l.minx) l.minx=(*it).x;
        if ((*it).x>l.maxx) l.maxx=(*it).x;
        if ((*it).y<l.miny) l.miny=(*it).y;
        if ((*it).y>l.maxy) l.maxy=(*it).y;
    }
    //cout<<l.maxx<<" "<<l.minx<<" "<<l.maxy<<" "<<l.miny<<endl;
    int dx=-l.minx, dy=-l.miny;
    //cout<<"dx: "<<dx<<" dy: "<<dy<<endl;
    set<point> tmp;
    for (set<point>::iterator it=l.pts.begin(); it!=l.pts.end(); ++it) {
        point newp((*it).x+dx, (*it).y+dy);
        tmp.insert(newp);
    }
    l.pts=tmp;
    l.minx+=dx; l.miny+=dy;
    l.maxx+=dx; l.maxy+=dy;
    return;
}
void rot (lattice& l)
{
    set<point> tmp;
    for (set<point>::iterator it=l.pts.begin(); it!=l.pts.end(); ++it) {
        point newp(-(*it).y, (*it).x);
        tmp.insert(newp);
    }
    l.pts=tmp;
    return;
}
void sym (lattice& l)
{
    set<point> tmp;
    for (set<point>::iterator it=l.pts.begin(); it!=l.pts.end(); ++it) {
        point newp((*it).x, -(*it).y);
        tmp.insert(newp);
    }
    l.pts=tmp;
    return;
}
void printL (lattice& l)
{
    //stdMove(l);
    char pic[11][11];
    memset(pic,'o',sizeof(pic));
    for (set<point>::iterator it=l.pts.begin(); it!=l.pts.end(); ++it) {
        pic[(*it).x][(*it).y]='#';
    }
    cout<<"lattice: "<<endl;
    for (int i=0; i<=l.maxx; ++i) {
        for (int j=0; j<=l.maxy; ++j) {
            cout<<pic[i][j];
        }
        cout<<endl;
    }
}
void printP (lattice& l)
{
    for (set<point>::iterator it=l.pts.begin(); it!=l.pts.end(); ++it) {
        cout<<"("<<(*it).x<<","<<(*it).y<<")"<<" ";
    }
    cout<<endl;
}
bool operator < (const lattice& l1, const lattice& l2)
{
    if (l1.pts.size()==l2.pts.size()) {
        set<point>::iterator it2=l2.pts.begin();
        for (set<point>::iterator it=l1.pts.begin(); it!=l1.pts.end(); ++it) {
            if ((*it)<(*it2)) return true;
            if ((*it2)<(*it)) return false;
            ++it2;
        }
    }
    return l1.pts.size()<l2.pts.size();
}
void solve(int w, int h, int n)
{
    const int dx[]={0,0,1,-1}, dy[]={1,-1,0,0};
    if (w<1||h<1) return;
    ans[1].insert(lattice(point(0,0)));
    for (int i=2; i<=n; ++i) {
        if (ans[i-1].empty()) break;
        for (set<lattice>::iterator it=ans[i-1].begin(); it!=ans[i-1].end(); ++it) {
            lattice tmp=*it; //if (i==5) printP(tmp);
            for (set<point>::iterator it1=tmp.pts.begin(); it1!=tmp.pts.end(); ++it1) {
                point tp=*it1;
                for (int j=0; j<4; ++j) {
                    /****
                    if (tmp.pts.find(point(tp.x+dx[j], tp.y+dy[j]))!=tmp.pts.end() && i==5) {
                        cout<<"find in: ";
                        printP(tmp);
                        cout<<"x="<<tp.x<<" y="<<tp.y<<" dx="<<dx[j]<<" dy="<<dy[j]<<endl<<endl;
                    }
                    ****/
                    if (tmp.pts.find(point(tp.x+dx[j], tp.y+dy[j]))==tmp.pts.end()) {
                        lattice tryy=tmp;
                        //if (i==5) {printL(tryy);printP(tryy);}
                        tryy.input(point(tp.x+dx[j], tp.y+dy[j]));
                        //if (i==5) {printP(tryy);cout<<"x="<<tp.x<<" y="<<tp.y<<" dx="<<dx[j]<<" dy="<<dy[j]<<endl;}
                        stdMove(tryy);
                        //if (i==5) {printL(tryy);printP(tryy); cout<<endl;}
                        if (tryy.maxx<w && tryy.maxy<h || tryy.maxx<h && tryy.maxy<w) {
                            bool flag=true;
                            if (ans[i].find(tryy)!=ans[i].end()) {flag=false; }
                            rot(tryy);
                            stdMove(tryy);
                            if (ans[i].find(tryy)!=ans[i].end()) {flag=false; }
                            rot(tryy);
                            stdMove(tryy);
                            if (ans[i].find(tryy)!=ans[i].end()) {flag=false; }
                            rot(tryy);
                            stdMove(tryy);
                            if (ans[i].find(tryy)!=ans[i].end()) {flag=false; }
                            sym(tryy);
                            stdMove(tryy);
                            if (ans[i].find(tryy)!=ans[i].end()) {flag=false; }
                            rot(tryy);
                            stdMove(tryy);
                            if (ans[i].find(tryy)!=ans[i].end()) {flag=false; }
                            rot(tryy);
                            stdMove(tryy);
                            if (ans[i].find(tryy)!=ans[i].end()) {flag=false; }
                            rot(tryy);
                            stdMove(tryy);
                            if (ans[i].find(tryy)!=ans[i].end()) {flag=false; }
                            if (flag) {
                                ans[i].insert(tryy);
                            }
                        }
                    }
                }
            }
        }
    }
}
int main ()
{
    int n, w, h;
    while (cin>>n>>w>>h) {
        solve(w,h, n);
        /***
        for (int i=1; i<=10; ++i) {
            if (ans[i].empty()) break;
            cout<<"n="<<i<<endl;
            for (set<lattice>::iterator it=ans[i].begin(); it!=ans[i].end(); ++it) {
                lattice l=*it;
                printL(l);
            }
            cout<<endl;
        }
        **/
        cout<<ans[n].size()<<endl;
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值