题目:输入n,w,h(1n10,1w,hn),求能放在w*h网格里的不同的n连块的个数(注意:平移、旋转、翻转后相同的算作同一种)。

分析:本题关键就是如何判重,有n个格子连通,所幸n很小,可以回溯求解,将网格放到坐标系中,旋转就是将x=y,y=-x,平移就是最小的点与原点距离,然后每个点都减去它,翻转就是x=x,y=-y,然后再旋转。所以可以用set来判重。因为取值范围很小,所以可以打表,将每个大小的网格1*1~10*10都搜索判断一遍1~10各个连通块的个数。

#include<cstdio>
#include<cstring>
#include<cctype>
#include<queue>
#include<iostream>
#include<vector>
#include<list>
#include<set>
using namespace std;
int n, w, h;
struct cell {int x, y;cell(){}cell(int _x,int _y):x(_x),y(_y){}bool operator<(const cell &u)const {if (x == u.x)return y < u.y;else return x < u.x;}
};
int dx[] = { 1,-1,0,0 };
int dy[] = { 0,0,1,-1 };
int ans[15][15][15];
typedef set<cell> poly;//n连通块
set<poly>blockmp[15];//所有个数的连通块
inline poly init_norimize(const poly &nlist) {//置原点int minx = 65536, miny = 65536;poly u;for (poly::iterator it = nlist.begin(); it != nlist.end(); ++it) {minx=min(minx, (*it).x);miny=min(miny, (*it).y);}for (poly::iterator it = nlist.begin(); it != nlist.end(); ++it) {u.insert(cell((*it).x - minx, (*it).y-miny));}return u;
}
inline poly rotate(const poly &nlist) {poly u;for (poly::iterator i = nlist.begin(); i != nlist.end(); i++)u.insert(cell(i->y, -i->x));return init_norimize(u);
}
inline poly mirror(const poly &nlist) {poly p;for (poly::iterator i = nlist.begin(); i != nlist.end(); i++)p.insert(cell(i->x, -i->y));return init_norimize(p);
}
bool isexist(poly nlist) {int len = nlist.size();//取得所求连通块的长度for (int i = 0; i < 4; i++) {nlist = rotate(nlist);if (blockmp[len].count(nlist)) {return true;}}nlist = mirror(nlist);for (int i = 0; i < 4; i++) {nlist = rotate(nlist);if (blockmp[len].count(nlist)) {return true;}}blockmp[len].insert(nlist);return false;
}
void dfs(const poly &nlist) {if (nlist.size() == n) {isexist(nlist);return;}for(cell it:nlist){for (int i = 0; i < 4; i++) {cell temp(it.x + dx[i], it.y + dy[i]);if (!nlist.count(temp)) {poly t = nlist;t.insert(temp);dfs(t);}}}
}
void buildtable() {memset(ans, 0, sizeof(ans));poly t;t.insert(cell(0, 0));blockmp[1].insert(t);for (n = 2; n <= 10; n++) {/*for (set<poly>::iterator it = blockmp[n - 1].begin(); it != blockmp[n - 1].end(); ++it) {poly x = *it;dfs(x);}*/for (poly itn : blockmp[n - 1]) //每次都从上一个列举的块进行迭代dfs(itn);}for (n = 2; n <= 10; n++) {for (w = 1; w <= 10; w++) {for (h = 1; h <= 10; h++) {int ant = 0;for (poly t1 : blockmp[n]) {int maxx = 0, maxy = 0;for (cell it1 : t1) {maxx = max(maxx, it1.x);maxy = max(maxy, it1.y);}if (min(maxx, maxy) < min(h, w)&&max(maxx,maxy)<max(h,w)) {ant++;}}ans[n][w][h] = ant;}}}
}
int main() {buildtable();while (scanf("%d%d%d", &n, &w, &h) == 3){if (n == 1) { printf("1\n"); continue; }//1的时候特判printf("%d\n", ans[n][w][h]);}//system("pause");return 0;
}

改进:

搜索连通块用的是回溯,但是因为每次搜索第n连通块时,都用的是n-1连通块将它每个格子的周围添加,实际上,不需要再递归,因为加一个正好等于n。

for(int n = 2; n <= maxn; n++) {for(set<Polyomino>::iterator p = poly[n-1].begin(); p != poly[n-1].end(); ++p)FOR_CELL(c, *p)for(int dir = 0; dir < 4; dir++) {Cell newc(c->x + dx[dir], c->y + dy[dir]);if(p->count(newc) == 0) check_polyomino(*p, newc);}}

完整老师代码:

#include<cstdio>#include<cstring>#include<algorithm>#include<set>using namespace std;struct Cell {int x, y;Cell(int x=0, int y=0):x(x),y(y) {};bool operator < (const Cell& rhs) const {return x < rhs.x || (x == rhs.x && y < rhs.y);}};typedef set<Cell> Polyomino;#define FOR_CELL(c, p) for(Polyomino::const_iterator c = (p).begin(); c != (p).end(); ++c)inline Polyomino normalize(const Polyomino &p) {int minX = p.begin()->x, minY = p.begin()->y;FOR_CELL(c, p) {minX = min(minX, c->x);minY = min(minY, c->y);}Polyomino p2;    FOR_CELL(c, p)p2.insert(Cell(c->x - minX, c->y - minY));return p2;}inline Polyomino rotate(const Polyomino &p) {Polyomino p2;FOR_CELL(c, p)p2.insert(Cell(c->y, -c->x));return normalize(p2);}inline Polyomino flip(const Polyomino &p) {Polyomino p2;FOR_CELL(c, p)p2.insert(Cell(c->x, -c->y));return normalize(p2);}const int dx[] = {-1,1,0,0};const int dy[] = {0,0,-1,1};const int maxn = 10;set<Polyomino> poly[maxn+1];int ans[maxn+1][maxn+1][maxn+1];// add a cell to p0 and check whether it's new. If so, add to the polyonimo setvoid check_polyomino(const Polyomino& p0, const Cell& c) {Polyomino p = p0;p.insert(c);p = normalize(p);int n = p.size();for(int i = 0; i < 4; i++) {if(poly[n].count(p) != 0) return;p = rotate(p);}      p = flip(p);for(int i = 0; i < 4; i++) {if(poly[n].count(p) != 0) return;p = rotate(p);}poly[n].insert(p);}void generate() {Polyomino s;s.insert(Cell(0, 0));poly[1].insert(s);// generatefor(int n = 2; n <= maxn; n++) {for(set<Polyomino>::iterator p = poly[n-1].begin(); p != poly[n-1].end(); ++p)FOR_CELL(c, *p)for(int dir = 0; dir < 4; dir++) {Cell newc(c->x + dx[dir], c->y + dy[dir]);if(p->count(newc) == 0) check_polyomino(*p, newc);}}// precompute answersfor(int n = 1; n <= maxn; n++)for(int w = 1; w <= maxn; w++)for(int h = 1; h <= maxn; h++) {int cnt = 0;for(set<Polyomino>::iterator p = poly[n].begin(); p != poly[n].end(); ++p) {int maxX = 0, maxY = 0;FOR_CELL(c, *p) {maxX = max(maxX, c->x);maxY = max(maxY, c->y);}if(min(maxX, maxY) < min(h, w) && max(maxX, maxY) < max(h, w))++cnt;} ans[n][w][h] = cnt;}}int main() {generate();int n, w, h;while(scanf("%d%d%d", &n, &w, &h) == 3) {printf("%d\n", ans[n][w][h]);}return 0;}

UVA1602 Lattice Animals 网格动物相关推荐

  1. UVA-1602 Lattice Animals 搜索问题(打表+set)

    题目链接 https://vjudge.net/problem/UVA-1602 紫书的一道例题,跟之前的很多题目有很多不同. 本题不像是一般的dfs或bfs这样的搜索套路,而是另一种枚举思路. 题意 ...

  2. UVA 1602 Lattice Animals

    https://vjudge.net/problem/UVA-1602 题意:w*h网格里放n连块,问有多少种放法 翻转.旋转90°.平移之后相同的算一种 推荐题解: http://blog.csdn ...

  3. UVa 1602:Lattice Animals(BFS)

    题目链接:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=841& ...

  4. 《算法竞赛入门经典(第2版)》——学习记录

    前言:   这里主要记录本人在学习紫书过程中充分理解过的题目的AC代码,便于以后回顾时查找代码和思路,毕竟看别人的真的有点难懂.此外,本书甚至是本书之外的相关知识学习也可能在此留下记录.   作为一只 ...

  5. 中英翻译《动物看见了什么》

    What animals see 动物看见了什么 一.Pre-reading activity 阅前思考 1.What animals do you like? 你喜欢什么动物? 2.Do you h ...

  6. 《题目与解读》红书 训练笔记目录《ACM国际大学生程序设计竞赛题目与解读》

    虽然2012年出版的老书了,但是是由三次世界冠军的上海交大ACM队出版的书籍,选择的题目是ACM经典中的经典,书中有非常详细的题解,可以学到很多东西,值得一刷. 目录 第一部分 第一章 数学 1.1 ...

  7. 0501 0503 模块区别_apollo介绍之planning模块(四)

    吾尝终日而思矣 不如须臾之所学也 - <劝学> Planning模块简介 规划(planning)模块的作用是根据感知预测的结果,当前的车辆信息和路况规划出一条车辆能够行驶的轨迹,这个轨迹 ...

  8. ACM题集以及各种总结大全(转)

    ACM题集以及各种总结大全! 虽然退役了,但是整理一下,供小弟小妹们以后切题方便一些,但由于近来考试太多,顾退役总结延迟一段时间再写!先写一下各种分类和题集,欢迎各位大牛路过指正. 一.ACM入门 关 ...

  9. Python教程:多态与多态性

    一.多态 Python中多态是指一类事物有多种形态.比如动物有多种形态,人,狗,猫,等等.文件有多种形态:文本文件,可执行文件. 二.多态性 1.什么是多态性? 多态性是指在不考虑实例类型的情况下使用 ...

最新文章

  1. 【设计模式】代理模式 ( 动态代理使用流程 | 创建目标对象 | 创建被代理对象 | 创建调用处理程序 | 动态创建代理对象 | 动态代理调用 )
  2. 白话Elasticsearch07- 深度探秘搜索技术之基于term+bool实现的multiword搜索底层剖析
  3. dm_php库,dmandwp系统 PHP建站系统+wordpress建站和DM系统区块+安装教程
  4. Win32汇编---控件的超类化感想
  5. POJ2146 Confusing Login Names [最小字符串编辑距离]
  6. pb中控件变颜色_基于GDI+技术开发工业仪表盘控件
  7. 卡巴斯基KEY被列入黑名单
  8. Qt编译Mysql驱动
  9. 网上书店管理系统 课程设计
  10. 【阅读笔记】BI系统介绍及建设思路
  11. Win7 无法安装 VMware Tools
  12. wifi(参数查看工具介绍)--研究(inSSIDer)
  13. 平均数、中位数、众数 三者的联系与区别
  14. [02.20][中国][人再囧途之泰囧][HD-RMVB.720p.国语中字][2012年喜剧]
  15. Unity3D插件 Doozy UI 学习(一):打开一个面板
  16. 腾讯 IVWEB 团队:前端识别验证码思路分析
  17. CVE-2021-42013:Apache HTTP Server目录遍历漏洞
  18. 重磅!项目经理指导手册和全套管理秘籍下载
  19. 37 | 什么是SLI、SLO、SLA
  20. FPGA开发——图像处理(包括MT9V034等摄像头学习笔记)

热门文章

  1. SpringBoot自动配置【源码分析】-初始加载自动配置类
  2. 什么是事务、半事务消息?怎么实现的?
  3. compareAndSwapInt
  4. 用户user空间和内核kernel空间
  5. 格式化输出字符串变量
  6. 服务提供者与服务消费者
  7. SpringMVC中向服务器传输数据(解决get、post、delete、put请求乱码问题)
  8. ThreadLocal - Java多线程编程
  9. 反向传播算法_反向传播算法:定义,概念,可视化
  10. linux 杀死脚本,linux – 如何在Bash脚本被杀死时杀死当前命令