题目大意

输入n,w,h(1<=n<=10,1<=w,h<=n).求能放在w*h网格里的不同的n连块的个数(平移,旋转,翻转算一种)

  首先,方法上有两个,一是打表,dfs构造连通块,枚举出来后再进行判重,另一种就是直接枚举每种连通块,保证每种连通块只枚举一次(这个方法还不会。。但可以访问en.wikipedia.org/wiki/Polyomino 进行学习)

  先看第一种方法:

    1.如何构造连通块?

    因为是构造连通块,所以就不能像寻找连通块或寻找路径那么做。。。一开始就犯了这种错误。。应该从大小为X(初始时X为1)的连通块开始,尝试从它的每一个边向外扩展,得到一个大小为X+1的连通块,并把这个连通块来判重,如果没有重,那么就将构成它的每一小块的坐标记录下来,为接下来用这个连通块构造更大的连通块做准备。如此循环往复,直到你求得大小为n的所有连通块。

    2.如何进行判重?

    判重也是这个题中很麻烦的一个点。。大体上的思路就是用存下每个连通块的状态,包括它们进行一系列变化后的状态。在存储这些千奇百怪的连通块时,务必保证把每个连通块顶着二维平面的左上角存,即以(0,0)为中心,将它们坐标标准化。(意会一下。。)如果你用的是set来存储以前构造到的连通块,那么你在判重的时候可以简单地用count函数,如果是其他数据类型,就只能挨个枚举比较了

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int maxn = 10;
struct cell {//块
int x, y;
cell(int x1, int y1):x(x1),y(y1) {}
bool operator<(const cell& a)const {//因为set需要定义<
return x < a.x || ((x == a.x) && y < a.y);
}
}; typedef set<cell> poly;//n连块
set<poly> poly_set[maxn+1];//poly_set[i]是含i个块的(规范化的poly)的集合
int ans[maxn+1][maxn+1][maxn+1];//存答案
int dx[4] = { -1,0,1,0 };
int dy[4] = { 0,1,0,-1 }; poly normalize(poly p) {//规范化,贴着左上角。可能并不占据(0,0)这个点。
poly newp;
int minx = p.begin()->x, miny = p.begin()->y;
for (auto q = p.begin(); q != p.end(); q++) {
minx = min(minx, q->x);
miny = min(miny, q->y);
}
for (auto q = p.begin(); q != p.end(); q++)
newp.insert(cell(q->x - minx, q->y - miny));
return newp;
}
poly rotate(poly p) {//顺指针旋转90°
poly newp;
for (auto q = p.begin(); q != p.end(); q++)
newp.insert(cell(q->y, -q->x));
return normalize(newp);
}
poly flip(poly p) {//上下翻转
poly newp;
for (auto q = p.begin(); q != p.end(); q++)
newp.insert(cell(q->x, -q->y));
return normalize(newp);
} void check_poly(poly p, cell& c) {//c能否放进p中
p.insert(c);
p = normalize(p);//规范化
int n = p.size();
//旋转八个方向,如果不存在的话加入到poly_set
for (int i = 0; i < 4; i++) {
if (poly_set[n].count(p))
return;
p = rotate(p);//顺时针旋转90°
}
p = flip(p);//翻转
for (int i = 0; i < 4; i++) {
if (poly_set[n].count(p))
return;
p = rotate(p);//顺时针旋转90°
}
poly_set[n].insert(p);
} void gen_poly() {//生成所有poly
for (int i = 1; i <= maxn; i++)
poly_set[i] = set<poly>();
//先生成含1个cell的poly
poly p1;
p1.insert(cell(0, 0));
poly_set[1].insert(p1);
//int c = 0; //用来看运算量 60000 在我的电脑上用了十几秒但交上去能过,挺玄学的
//根据含i-1个cell的poly_set推出含i个的poly_set
for (int i = 2; i <= maxn; i++)
for (auto p = poly_set[i - 1].begin(); p != poly_set[i - 1].end(); p++)
//p类型是set<poly>::iterator
for (auto q = p->begin(); q != p->end(); q++) {
//q类型是set<cell>::iterator ,也就是poly::iterator
for (int j = 0; j < 4; j++) {
/*if (c++ % 10000==0) {
cout << c / 10000;
}*/ cell newc(q->x + dx[j], q->y + dy[j]);
if (!p->count(newc))//p中没有newc这个cell,就加入
check_poly(*p, newc);//别忘p是迭代器
}
}
for (int i = 1; i <= maxn; i++)//i连块
for (int w = 1; w <= i; w++)
for (int h = 1; h <= i; h++) {
int count = 0;
for (auto p = poly_set[i].begin(); p != poly_set[i].end(); p++) {
int maxx = p->begin()->x, maxy = p->begin()->y;
for (auto q = p->begin(); q != p->end(); q++) {
maxx = max(maxx, q->x);
maxy = max(maxy, q->y);
}
if(min(maxx,maxy)<min(w,h)&&max(maxx,maxy)<max(h,w))
//因为有两种摆法:横放或竖放。是(maxx<w&&maxy<h)||(maxx<h&&maxy<w)的简写
//为什么没有等于?因为规范化的时候左上角是(0,0)
count++;
}
ans[i][w][h] = count;
}
} int main() {
gen_poly();//生成所有poly并存答案
cout << 1;
int n, w, h;
while (scanf_s("%d %d %d", &n, &w, &h) == 3)
cout << ans[n][w][h] << endl;
return 0;
}

  从做这道题的过程中又能学到什么?

  1.状态的记录方式可以灵活。比如这一个题,就没有死板地记录每一种连通块旋转,对称后的样子,而是通过flip,rotate等几个函数临时处理,既提高了效率,又简洁了代码。

  2.枚举连通块时,可以通过以前枚举过的连通块向外扩展

 3关于set的灵活使用.这一道题利用了set的count和有序的性质方便了判重的进行,同时在迭代的过程中的迭代器使用方法也值得学习

网格动物UVA1602的更多相关文章

  1. UVA1602 Lattice Animals 网格动物 (暴力,STL)

    多联骨牌的生成办法,维基上只找到固定的骨牌fix,而free的没有找到. 于是只好写个set判重的简单枚举了. 旋转的操作,可以在坐标轴上画个点,以原点为轴心,逆时针旋转90度,新的点的坐标为(-y, ...

  2. UVa 1602 网格动物(回溯)

    https://vjudge.net/problem/UVA-1602 题意:计算n连通块不同形态的个数. 思路: 实在是不知道该怎么做好,感觉判重实在是太麻烦了. 判重就是判断所有格子位置是否都相同 ...

  3. ACM题目————网格动物

    Lattice animal is a set of connected sites on a lattice. Lattice animals on a square lattice are esp ...

  4. 从零开始一起学习SLAM | 点云到网格的进化

    点击公众号"计算机视觉life"关注,置顶星标更快接收消息! 本文编程练习框架及数据获取方法见文末获取方式 菜单栏点击"知识星球"查看「从零开始学习SLAM」一 ...

  5. 支持向量机(SVM)利用网格搜索和交叉验证进行参数选择

    上一回有个读者问我:回归模型与分类模型的区别在哪?有什么不同,我在这里给他回答一下 : : : : 回归问题通常是用来预测一个值,如预测房价.未来的天气情况等等,例如一个产品的实际价格为500元,通过 ...

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

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

  7. C#中如何创建PDF网格并插入图片

    这篇文章我将向大家演示如何以编程的方式在PDF文档中创建一个网格,并将图片插入特定的网格中. 网上有一些类似的解决方法,在这里我选择了一个免费版的PDF组件.安装控件后,创建新项目,添加安装目录下的d ...

  8. pcl曲面网格模型的三种显示方式

    pcl网格模型有三种可选的显示模式,分别是面片模式(surface)显示,线框图模式(wireframe)显示,点模式(point)显示.默认为面片模式进行显示.设置函数分别为: void pcl:: ...

  9. 从点云到网格(三)Poisson重建

    Possion重建是Kazhdan等2006年提出的网格重建方法[1].Possion重建的输入是点云及其法向量,输出是三维网格.Poisson有公开的源代码[2].PCL中也有Poisson的实现. ...

随机推荐

  1. SQL注入靶场

    靶场搭建 系统环境&工具 环境采用centos7的版本(纯命令行),采用一键部署平台,phpstudy工具,安装教程链接:https://www.xp.cn/linux.html#instal ...

  2. WinUI迁移到即将"过时"的.NET MAUI个人体验

    迁移的初衷 本人平时是做.net相关的工作,对于.net技术栈也有一些了解,自从新的.net能够跨平台之后,之前也有跨平台的ui框架Xamarin,现在微软推出了.NET MAUI这个说是 统一了开发 ...

  3. 274. H-Index - LeetCode

    Question 274. H-Index Solution 题目大意: 论文里的 h 因子判定,题目的意思可能有点晦涩.h 因子是评判学术成就的一种重要方法,h 因子越高越好,h 因子兼顾研究学术人 ...

  4. Maven生成可以直接执行的jar包

    要想jar包能直接通过java -jar xxx.jar运行,需要满足: 1.在jar包中的META-INF/MANIFEST.MF中指定Main-Class,这样才能确定程序的入口在哪里: 2.要能 ...

  5. 源码解读etcd heartbeat,election timeout之间的拉锯

    转一个我在知乎上回答的有关raft election timeout/ heartbeat interval 的回答吧. 答:准确来讲: election是timeout,而heartbeat 是in ...

  6. C#/VB.NET 在PDF表格中添加条形码

    条码的应用已深入生活和工作的方方面面.在处理条码时,常需要和各种文档格式相结合.当需要在文档中插入.编辑或者删除条码时,可借助于一些专业的类库工具来实现.本文,以操作PDF文件为例,介绍如何在编辑表格 ...

  7. 抽象类与接口——JavaSE基础

    抽象类与接口 抽象类 抽象类既包含规范又包含具体实现 抽象类可以包含实现的方法 和 未实现的用abstract修饰的抽象方法 抽象类不可以有实例化(不能使用new实例化),只能通过子类继承,然后对子类 ...

  8. Egg上层框架CabloyJS是如何输出SQL语句日志的?

    背景 在Egg开发实践中,经常会遇到一个问题:如何查看刚刚执行过的Egg组装的原生SQL语句呢? 1. 现有方案 可以直接在项目的config配置文件中添加MySQL配置debug: true.这会启 ...

  9. zigbee技术数传电台在石油探井状态监测系统

    石油探井分布分散,数量众多,出现异常现象需及时处理.人工巡视耗时长.时效性差:有线传输存在布线繁琐.成本高.现场无移动网络覆盖等诸多缺点. 现需要一种支持大量接入.覆盖范围广.数据传输高效且有数据中心 ...

  10. Hash表、 继承

    Hash表 我们来了解什么是Hash表?? 要想知道什么是哈希表,那得先了解哈希函数 二叉平衡树 红黑树 B B+树,它们的查找都是先从根节点进行查找,从节点取出数据或索引与查找值进行比较.那么,有没 ...