题意:由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;
}