いろいろがんばりたいブログ

情報科学科の人がいろいろ書きます。

Generating Polynomino in C++

http://en.wikipedia.org/wiki/Polyomino

one-handedなもの。つまり回転による同型は無視する。また、穴があるものはなしとする。

#include <iostream>
#include <iomanip>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <bitset>
#include <stack>
#include <utility>
#include <numeric>
#include <algorithm>
#include <functional>
#include <complex>
#include <string>
#include <sstream>

#include <cstdio>
#include <cstdlib>
#include <cctype>
#include <cstring>

using namespace std;

template<typename T>
ostream& operator<<(ostream& os,const vector<T>& val){
    os << "[ ";
    for(typename vector<T>::const_iterator it=val.begin();
        it != val.end();++it){
        os << *it << " ";
    }
    os << "]";
    return os;
}

struct Block{
    int x,y;
    Block(int _x,int _y) : x(_x),y(_y) {}
    // 0 1 2 3 4
    inline Block rotate() const{
        return Block(-y,x);
    }
    inline Block shift(const int &dx,
                       const int &dy) const{
        return Block(x+dx,y+dy);
    }
    bool operator<(const Block& rhs) const{
        if(x != rhs.x) return x < rhs.x;
        else return y < rhs.y;
    }
    bool operator==(const Block& rhs) const{
        return x == rhs.x and y == rhs.y;
    }
};

ostream& operator<<(ostream& os,const Block& b){
    os << "(" << b.x << "," << b.y << ")";
    return os;
}
ostream& operator<<(ostream& os,const set<Block>& b){
    os << "[";
    for(const auto& a : b){
        os << a << ",";
    }
    os << "]";
    return os;
}

set<Block> rotate_block(const set<Block>& base){
    set<Block> new_blocks;
    for(const auto& b : base){
        new_blocks.insert(b.rotate());
    }
    return new_blocks;
}

set<Block> regularize_block(const set<Block>& base){
    int mx = 1<<30,my=1<<30;
    for(const auto& b : base){
        mx = min(mx,b.x);
        my = min(my,b.y);
    }
    set<Block> new_blocks;
    for(const auto& b : base){
        new_blocks.insert(b.shift(-mx,-my));
    }
    return new_blocks;
}

const vector<int> dx = {1,0,-1,0};
const vector<int> dy = {0,1,0,-1};


void generate_blocks(const size_t& n,const set<Block>& base,
                     set<set<Block>>& S){
    if(base.size() == n) return;
    for(const auto& b : base){
        for(size_t i=0;i<min(dx.size(),dy.size());i++){
            Block new_block(b.x+dx[i],b.y+dy[i]);
            if(base.find(new_block) != base.end()) continue;
            set<Block> new_base = base;
            new_base.insert(new_block);
            new_base = regularize_block(new_base);
            bool is_new = true;
            for(int j=0;j<4;j++){
                is_new = is_new and (S.find(new_base) == S.end());
                new_base = rotate_block(new_base);
                new_base = regularize_block(new_base);
            }
            new_base = rotate_block(new_base);
            new_base = regularize_block(new_base);
            if(is_new){
                S.insert(new_base);
                generate_blocks(n,new_base,S);
            }
        }
    }
    return;
}


int main(){
    set<set<Block>> S;
    Block root(0,0);
    S.insert({root});
    const int N = 10;
    generate_blocks(N,{root},S);
    vector<vector<set<Block>>> bs(N+1);

    int cnt = 0;
    for(const auto& b : S){
        bs[b.size()].push_back(b);
    }
    for(const auto& b : bs){
        cout << b.size() << endl;
    }
    cerr << cnt << endl;
    return 0;
}