uva1602:回溯+判重

题解:这一题思路很清晰,就是回溯+判重。但是难点在于判重。旋转、平移、翻转该怎么统一呢?参考了大佬的代码,终于豁然开朗。

  • 首先判重想到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]);
	}
}

 

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值