UVA1602 Lattice Animals 回溯+set判重
来源:互联网 发布:网络直销不合法 编辑:程序博客网 时间:2024/05/16 14:18
按照题意,只要我们能找出所有n连块,然后再判断能不能放进w*h的方格中就行了。找出所有n连块可以用回溯法,从k连块搜索,通过在其周围放一个方块,从而得到k+1连块,从而这样不断搜索下去直到n连块,搜索过程的判重就交给set了。因为题目中有多组输入,假如连续输入1000组相同的数据,我们都要一遍一遍的dfs吗?显然太复杂。所以我们可以事先把所有可能的输入数据对应的答案打表,这样输出就快的多了。在打表的时候又面临一个问题了,我们要得到所有的4连块,就要从1连块开始dfs,要得到所有的5连块,也要从1连块开始dfs,这样不是显得太笨拙了吗?同时我们写的这种最简单的枚举方法,使得每一种n连块都被枚举了很多次,所以上面那种笨拙的方法是肯定不能用的,必然会TLE。那么怎么做呢?假如我们要得到所有的5连块,我们就可以通过刚刚已经搜索的4连块得出,这样就简化了搜索过程。开始写代码面临的第一个问题就是如何表示n连块的状态,我们可以把n连块想成是n个坐标的集合,用set实现就可以了。下面是具体实现过程:
#include <iostream>#include <cstdlib>#include <cstdio>#include <cstring>#include <set>#define INF 0x3f3f3fusing namespace std;const int dx[] = {-1, 1, 0, 0};//方向数组const int dy[] = {0, 0, -1, 1};int n, w, h;int ans[15][15][15];//所有输入对应的答案struct cell//定义单元格{ int x, y; cell(int a, int b) { x = a; y = b; } cell(){} bool operator <(const cell &rhs) const { if (x != rhs.x) return x < rhs.x; return y < rhs.y; }};typedef set<cell> poly;//n个坐标的集合也就是一个n连块set<poly> vis[15];//用来判重的set,vis[n]是被访问过的所有n连块的集合poly initial_normal(const poly &p)//将这个n连块标准化成左上角在(0,0)点{ poly goal; int minx = INF, miny = INF; for (cell it : p) { minx = min(minx, it.x); miny = min(miny, it.y); } for (cell it : p) goal.insert((cell){it.x - minx, it.y - miny}); return goal;}inline poly rotate(const poly &p)//顺时针旋转转90°,千万记住末尾返回的应该是标准化之后的答案{ //因为有的n连块顺时针旋转90°之后出界了,需要将其标准化。 poly goal; //因为这个函数会被执行多次,用inline可以加快执行速度 for(poly::iterator i=p.begin(); i!=p.end(); i++) goal.insert(cell(i->y, -i->x)); return initial_normal(goal);}inline poly flip(const poly &p)//将一个n连块沿x轴翻转,同时也要将答案标准化{ poly goal; for(poly::iterator i=p.begin(); i!=p.end(); i++) goal.insert(cell(i->x,-i->y)); return initial_normal(goal);}bool had_vis(poly p)//判断一个n连块是否访问过,没访问过就插入到vis里面,返回false{ int len = p.size(); for (int i=0; i<4; i++) { p = rotate(p); if (vis[len].count(p)) return true; } p = flip(p);//将p翻转之后,再次顺时针旋转看出现过没有 for (int i=0; i<4; i++) { p = rotate(p); if (vis[len].count(p)) return true; } vis[len].insert(p); return false;}void dfs(const poly &p)//由当前k连块dfs到n连块{ if (p.size() == n) { had_vis(p); return; } for (cell cur : p) { for (int d=0; d<4; d++) { cell next(cur.x + dx[d], cur.y + dy[d]); //if(next.x >= 0 && next.x < w && next.y >= 0 && next.y < h && !p.count(next)) //刚开始这里是这样写的,最后答案错误,想了很久才发现。现在的目标不是dfs出 //一个可以装进w*h网格中的n连块,现在的目的是dfs出所有的n连块,所以不在乎能不能装进去 if (!p.count(next)) { poly p_next = p; p_next.insert(next); dfs(p_next); } } }}void print_table()//将所有可能的输入打表{ memset(ans, 0, sizeof(ans)); poly S; S.insert(cell(0, 0));//得到1连块 vis[1].insert(S); for (n=2; n<=10; n++)//首先搜索n = 10的情况,这样搜索一遍后,vis里面 { //就含有了所有大小的连通块。搜索k连块是借用的k-1连块的搜索结果。 for (poly it1 : vis[n - 1]) dfs(it1); } for (n=2; n<=10; n++)//对所有可能打表 for (w=1; w<=10; w++) for (h=1; h<=10; h++) { int cnt=0; for (poly it1 : vis[n]) { int maxx=0,maxy=0; for (cell it2 : it1)//寻找当前的连通块的最大的x,y { maxx = max(maxx, it2.x); maxy = max(maxy, it2.y); } //能够放入w*h网格内的条件 if(min(maxx, maxy) < min(h, w) && max(maxx, maxy) < max(h, w)) cnt++; } ans[n][w][h]=cnt; }}int main(){ print_table(); while (scanf("%d%d%d", &n, &w, &h)==3) { if (n == 1) {printf("1\n");continue;}//1的时候特判 printf("%d\n", ans[n][w][h]); } return 0;}
0 0
- UVA1602 Lattice Animals 回溯+set判重
- Uva1602 Lattice Animals 【枚举打表+形状判重】【例题7-14】
- UVa1602 - Lattice Animals
- [Uva1602][Poj2170][Zoj2669][Northeastern Europe 2004] Lattice Animals 【set+傻瓜搜索】
- 搜索 【uva1602】Lattice Animals (练习题7-14 网格动物)
- 例题7-14 网格动物(Lattice Animals, ACM/ICPC NEERC 2004, UVa1602)
- uva1602 无方向位置的姿势判重
- 1602 - Lattice Animals
- UVa 1602 Lattice Animals
- 1602 - Lattice Animals
- UVA 1062 Lattice Animals
- Lattice Animals UVA
- uva 1602 Lattice Animals
- hdu4277 dfs+set判重
- 1151. 魔板(用set判重)
- hdu4277 USACO ORZ(dfs+set判重)
- poj 3050 dfs+set判重
- poj 1007 双向bfs+set判重
- CSS多列布局方案
- Days30 PullToRefreshListView & SlidingMenu
- 浅谈 C++ 中的 new/delete 和 new[]/delete[]
- Java中了使用list方式查看输入的字符串中不重复的字符
- discuz主导航左右分栏
- UVA1602 Lattice Animals 回溯+set判重
- Hibernate关联关系配置(一对多、一对一和多对多)
- 不忘初心
- 运算符
- Java内存模型以及volatile关键字
- 给定链表中某个节点的指针,删除链表中的该节点
- Python实现二叉树
- javascript中数组的方法
- 大规模SOA系统中的分布事务处事_程立