题解:这一题思路很清晰,就是回溯+判重。但是难点在于判重。旋转、平移、翻转该怎么统一呢?参考了大佬的代码,终于豁然开朗。
- 首先判重想到set,这里要用的双set,代码里有说明。
- 旋转操作,每次旋转90度,就是(x,y)-->(y,-x)
- 平移操作,找出整个图形的x和y坐标的最小值,然后每个图形相应的平移。
- 翻转,就是(x,y)-->(y,x),但是翻转完之后,还有经过旋转判重。因为旋转有四种形态,翻转完之后旋转又有4种。
- 剩下的参考代码,这里用了预处理。
代码:
#include <bits/stdc++.h>
#define ssit set< set<Cell> >::iterator
#define sit set<Cell>::iterator
using namespace std;
int const MAX = 11;
int dir[4][2] = {1,0,0,1,-1,0,0,-1};
struct Cell //储存每一个点
{
int x,y;
Cell(int x = 0, int y = 0) :x(x),y(y){}
bool operator<(const Cell &b) const {
return (x == b.x&&y < b.y) || x < b.x;
}
};
set<set<Cell> >p[MAX]; //set<Cell>保存单个连续的图形,set<set<Cell> >保存为某一个n的多个图形的集合
int ans[MAX][MAX][10]; //预处理保存答案
inline set<Cell> Move(const set<Cell> & s){
set<Cell>tmp;
int mx = 11,my = 11; //初始化
for(sit it = s.begin();it != s.end();it++){
mx = min(mx,it->x);
my = min(my,it->y);
}
for(sit it = s.begin();it != s.end();it++)
tmp.insert(Cell(it->x - mx,it->y - my));
return tmp;
}
inline set<Cell> rotation(const set<Cell> & s){
set<Cell>tmp;
for(sit it=s.begin();it != s.end();it++)
tmp.insert(Cell(it->y,-it->x));
return Move(tmp);
}
inline set<Cell> flip(const set<Cell> & s){
set<Cell> tmp;
for(sit it=s.begin();it != s.end();it++)
tmp.insert(Cell(it->y,it->x));
return Move(tmp);
}
inline void Add(const set<Cell>& g,const Cell &newc){ 以这个图形为基础插入一个连续的点,并且判重
set<Cell> s = g;
s.insert(newc);
s = Move(s);
int n = s.size();
for(int i=0;i<4;i++){ //进行旋转,判重
if(p[n].count(s)) return;
s = rotation(s);
}
s = flip(s);
for(int i=0;i<4;i++){
if(p[n].count(s)) return;
s = rotation(s);
}
p[n].insert(s);
}
void pre(){
set<Cell>fir; fir.insert(Cell(0,0));
p[1].insert(fir); //只有一个点
for(int i=2;i<=10;i++){
for(ssit it = p[i-1].begin();it != p[i-1].end();it++) //枚举每一个图形
for(sit it1 = it->begin();it1 != it->end(); it1++){ //枚举每一个点
for(int j=0;j<4;j++){
//cout<<p[i-1].size()<<endl;
Cell tmp(it1->x + dir[j][0],it1->y + dir[j][1]);
if(!it->count(tmp)) Add(*it,tmp);
}
}
}
for(int i=1;i<=10;i++){ //枚举n
for(int j=1;j<=10;j++){
for(int k=1;k<=10;k++){
int cnt = 0;
for(ssit it=p[i].begin();it != p[i].end();it++){
int mx = 0,my = 0;
for(sit it1 = (*it).begin();it1 != (*it).end();it1++){
mx = max(it1->x,mx);
my = max(it1->y,my);
}
if(min(mx,my) < min(j,k) && max(mx,my) < max(j,k)) cnt++;
}
ans[i][j][k] = cnt;
}
}
}
}
int main(){
pre();
int n,w,h;
while(scanf("%d%d%d",&n,&w,&h) == 3){
printf("%d\n",n == 1 ? 1 : ans[n][w][h]);
}
}