题目链接:UVa 1602 Lattice Animals 网格动物
题目翻译请见《入门经典》 P212
分析:
提问很多,每次搜一次你就炸了,只有先处理出所有的答案,也就是打表大法!
本题没有什么剪枝,直接暴力即可,主要是有以下三个问题:
(1)怎么存储一个连块
(2)怎么处理旋转,平移和翻转
(3)怎么判重
对于存储,采用一个坐标的集合来表示连块 ,坐标用pair 来存储,连块就用set< pair<int,int> >。
存储的所有连块,都先进行标准化,也就是把最左上的点放到(0,0)的位置,这样也就处理了平移的操作。
对于旋转,不妨考虑顺时针旋转90 度, 使用坐标变换 (x,y)->(y,-x)。
对于翻转,坐标变化为(x,y)->(x,-y)
注意,旋转或者翻转之后都要标准化!
讨论的先后也是本题的关键: 如果先定下w,h搜索不超过范围的连块就重复搜索了很多情况,所以不妨先扩展出所有的连块,再讨论w*h的格子装不装得下。
代码如下:
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cmath>
#include<set>
#define PII pair<int,int>
#define iter set<PII>:: iterator
#define xx first
#define yy second
#define CLEAR(xxx) memset(xxx,0,sizeof(xxx))
using namespace std;
const int maxn=10+5,inf=0x3f3f3f3f;
const int dx[4]={-1,1,0,0},dy[4]={0,0,-1,1};
int n,w,h;
int ans[maxn][maxn][maxn];
typedef set<PII> poly; //连块
set<poly> vis[15];
void Print(poly p){ //调试用: 打印这个连块
int size=p.size();
cout<<"A ploy of size "<<size<<": \n";
for(iter it=p.begin(); it!=p.end(); it++)
cout<<"cell : ("<<it->xx<<" , "<<it->yy<<" ) "<<endl;
}
inline poly Standardize(poly p){ //标准化:把最左上的点移到(0,0)
int Minx=inf,Miny=inf;
poly ret;
iter it;
for(it=p.begin();it!=p.end();it++)
Minx=min(Minx,it->xx),Miny=min(Miny,it->yy);
for(it=p.begin();it!=p.end();it++)
ret.insert(make_pair(it->xx-Minx,it->yy-Miny));
return ret;
}
inline poly Rotate(poly p){ //顺时针旋转90度 (x,y) -> (y,-x)
poly ret;
for(iter it=p.begin(); it!=p.end(); it++)
ret.insert(make_pair(it->yy,-(it->xx) ));
return Standardize(ret);
}
inline poly Flip(poly p){ //翻转 (x,y)->(x,-y)
poly ret;
for(iter it=p.begin(); it!=p.end(); it++)
ret.insert(make_pair(it->xx,-(it->yy)));
return Standardize(ret);
}
bool Check(poly p){ //检查该连块(已标准化) 有没有出现过 ,如果没有,插入Vis集合中
int i,size=p.size();
if(vis[size].count(p)) return false;
for(i=0;i<4;i++){
p=Rotate(p);
if(vis[size].count(p)) return false;
}
p=Flip(p);
if(vis[size].count(p)) return false;
for(i=0;i<4;i++){
p=Rotate(p);
if(vis[size].count(p)) return false;
}
vis[size].insert(p);
return true;
}
void DFS(poly p){ //由当前k连块扩展出k+1 连块
if(p.size()==n){
Check(p);
return ;
}
for(iter it=p.begin(); it!=p.end() ; it++){
for(int i=0;i<4;i++){
PII cur;
cur.xx=it->xx+dx[i]; cur.yy=it->yy +dy[i];
if(!p.count(cur)){
poly temp=p;
temp.insert(cur);
DFS(temp);
}
}
}
}
void Make_Table(){ //提问次数多,先计算好所有答案
poly S;
S.insert(make_pair(0,0)); //1连块
vis[1].insert(S);
for(n=2;n<=10;n++){
set<poly> :: iterator it;
for(it=vis[n-1].begin();it!=vis[n-1].end(); it++)
DFS(*it);
}
for(n=1;n<=10;n++){
set<poly>::iterator it;
for(it=vis[n].begin(); it!=vis[n].end(); it++){
int Maxx=0,Maxy=0;
for(iter i=it->begin();i!=it->end(); i++){
Maxx=max(Maxx,i->xx);
Maxy=max(Maxy,i->yy);
}
if(Maxx<Maxy) swap(Maxx,Maxy);
for(w=1;w<=10;w++)
for(h=1;h<=10;h++)
if(Maxx<max(w,h) && Maxy<min(w,h)) ans[n][w][h]++;
}
}
}
int main(){
Make_Table();
while(scanf("%d%d%d",&n,&w,&h)==3)
printf("%d\n",ans[n][w][h]);
return 0;
}