UVA1602 Lattice Animals 搜索+剪枝

题目大意

  给出一个$w\times h$的网格,定义一个连通块为一个元素个数为$n$的方格的集合$A,\forall x\in A, \exists y\in A$,使得$x,y$有一条公共边。现要求一个元素个数极多的连通块的集合$K_N$,使得$\forall A,B\in K_n$,不存在一种由对称、旋转、平移组成的操作$f(A)$,使得$f(A)=B$。求$|K|$。$w\leq h\leq n\leq 10$。

题解

  这道题可把我恶心到吐了。。。

主体算法

错误算法1

  跟宝藏一题的思路一样,把两个相邻的块看作由一条边连接的两个节点,随后枚举生成树的个数$m$即可。最后输出的结果便是$\frac{m}{8}$(对称/2,旋转再/4)。

  这种做法错因在于不同的连通块可以对应不同的生成树,而且连通块可能会有轴对称或旋转对称等。以后遇到像这样复杂得连手推样例都不愿做的算法就不要再使用了。

错误算法2

  对于每一组数据,进行Dfs搜索。将Dfs搜索到的连接块用set记录,它的作用一是防止一个连通块被访问多次。二是防止等价的最终连通块使答案变多,实现是要将最终连通块本身以及经过对称旋转后的变化图形卡在网格的左上角。

  这种做法错在多组数据都要重算一遍,时间复杂度太高。

正确算法

  我们运用打表的思想,Bfs将$10\times 10$网格内的$K_n, n=1,2,\cdots 10$全部预处理出来保存在set<Block> Ans[15]中,给出$n,w,h$,则在Ans[n]中找到符合条件(注意:对于长径和宽径不同的连通块,不但要看看正常放能不能放入网格中,还要看看把它旋转90°后能不能放入)的连通块即可。

  怎么Bfs呢?Bfs的每一层按照连通块内格子的个数进行分类。Bfs的起点是一个只有格子(1, 1)的连通块。每一个Ans[n]内的连通块都是恰好卡到左上角的连通块。Ans[i]由Ans[i - 1]扩展得来,对于Ans[i - 1]中的每个连通块$A$,尝试找出两个相邻的网格$a, b, a\in A, b\notin A$,若它经过各种变换后的图形在Ans[i]中都没有出现,则将该连通块加入Ans[i]。

  问题来了,如何处理下列情况呢?

  如果我们就在网格的限制内扩展,这种扩展就不可能。所以我们可以尝试扩展到整个网格以外,然后卡到左上角的方法达到这个目的。因为每次只扩展一个格子,所以这种方法可行。

  不过这时我们不要忘了特判不合法的情况:

矩阵操作

方法一

  在每个连通块内维护一个set,维护每个在连通块内的网格的坐标。

  这样处理有些麻烦。

方法二

  每个连通块用二维数组存储,变换以整个网格的某个位置作为中心或轴。

  这个时候旋转90°操作就比较膈应人了。我们不可以以整个网格的中心作为轴,因为。。。待会,到底是旋转到哪儿去?中心是哪儿?  我们不如直接以(0, 0)作为中心旋转,将旋转过后的坐标用vector存储起来,然后将vector内的所有网格(row, col)加上(dRow, dCol)再存储起来。

  这种做法就是感觉有些不专业。。。

最终做法

  每个连通块用二维数组存储,操作在连通块所在矩形内操作。

  如图蓝色的矩形即为红色连通块对应的矩形。

  此时如何旋转90°呢?我们要用矩阵转置的方法。

 

然后这个程序就在50ms内通过了。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <set>
#include <cassert>
using namespace std;#define UpdateMin(x, y) x = min(x, y)
#define UpdateMax(x, y) x = max(x, y)const int MAX_POS_ARG_SIZE = 15, INF = 0x3f3f3f3f, MINF = 0xcfcfcfcf;
const int TotRow = 10, TotCol = 10, TotNode = 10;
const int Dir[4][2] = { {0, 1}, {1, 0}, {0, -1}, {-1, 0} };struct Block
{bool A[MAX_POS_ARG_SIZE][MAX_POS_ARG_SIZE];Block(){memset(A, 0, sizeof(A));}bool operator < (const Block& a) const{return memcmp(A, a.A, sizeof(A)) == -1;}bool operator == (const Block& a) const{return memcmp(A, a.A, sizeof(A)) == 0;}Block operator = (const Block& a){memcpy(A, a.A, sizeof(A));return *this;}void GetRect(int &minRow, int &maxRow, int &minCol, int &maxCol)//所在矩形{minRow = minCol = INF;maxRow = maxCol = MINF;for (int row = 0; row <= TotRow; row++)for (int col = 0; col <= TotCol; col++)if (A[row][col]){UpdateMin(minRow, row);UpdateMax(maxRow, row);UpdateMin(minCol, col);UpdateMax(maxCol, col);}}void GetSq(int &minRow, int &maxRow, int &minCol, int &maxCol)//所在正方形{GetRect(minRow, maxRow, minCol, maxCol);int eLen = max(maxRow - minRow + 1, maxCol - minCol + 1);maxRow = minRow + eLen - 1;maxCol = minCol + eLen - 1;}Block GetFlipHor(){Block ans;int minRow, maxRow, minCol, maxCol;GetRect(minRow, maxRow, minCol, maxCol);for (int row = minRow; row <= maxRow; row++)for (int col1 = minCol, col2 = maxCol; col1 <= maxCol; col1++, col2--)ans.A[row][col2] = A[row][col1];return ans;}Block GetRotate90(){Block ans;int minRow, maxRow, minCol, maxCol;GetRect(minRow, maxRow, minCol, maxCol);for (int row = 1; row <= maxCol; row++)for (int col = 1; col <= maxRow; col++)ans.A[row][col] = A[maxRow -col +1][row];return ans;}Block GetNormal(){Block ans;int minRow, maxRow, minCol, maxCol;GetRect(minRow, maxRow, minCol, maxCol);for (int row = minRow; row <= maxRow; row++)for (int col = minCol; col <= maxCol; col++)ans.A[row - minRow + 1][col - minCol + 1] = A[row][col];return ans;}bool Invalid(int totNode){int minRow, maxRow, minCol, maxCol;GetRect(minRow, maxRow, minCol, maxCol);return maxRow - minRow + 1 > totNode || maxCol - minCol + 1 > totNode;}
};set<Block> Ans[MAX_POS_ARG_SIZE];bool Exists_Rotate(set<Block> &ans, Block cur)
{if (ans.count(cur))return true;for (int i = 1; i <= 3; i++){cur = cur.GetRotate90();if (ans.count(cur))return true;}return false;
}bool Exists(set<Block> &ans, Block cur)
{if (Exists_Rotate(ans, cur))return true;if (Exists_Rotate(ans, cur.GetFlipHor().GetNormal()))return true;return false;
}void MakeAnsList()
{Block start;start.A[1][1] = true;Ans[1].insert(start);for (int i = 2; i <= TotNode; i++){for (set<Block>::iterator it = Ans[i - 1].begin(); it != Ans[i - 1].end(); it++){for (int row = 1; row <= TotRow; row++)for (int col = 1; col <= TotCol; col++){if (it->A[row][col]){for (int k = 0; k < 4; k++){int nextRow = row + Dir[k][0], nextCol = col + Dir[k][1];if (nextRow < 0 || nextRow > TotRow || nextCol < 0 || nextCol > TotCol)continue;if (it->A[nextRow][nextCol])continue;Block next = *it;next.A[nextRow][nextCol] = true;if (next.Invalid(i))continue;next = next.GetNormal();if (Exists(Ans[i], next))continue;Ans[i].insert(next);}}}}}
}int GetAns(int totNode, int totRow, int totCol)
{int ans = 0;for (set<Block>::iterator it = Ans[totNode].begin(); it != Ans[totNode].end(); it++){Block temp = *it;int minRow, maxRow, minCol, maxCol;temp.GetRect(minRow, maxRow, minCol, maxCol);assert(minRow == 1 && minCol == 1);if (maxRow <= totRow && maxCol <= totCol || maxCol <= totRow && maxRow <= totCol){Block a = *it;ans++;}}return ans;
}int main()
{MakeAnsList();int totNode, totRow, totCol;while (~scanf("%d%d%d", &totNode, &totRow, &totCol))printf("%d\n", GetAns(totNode, totRow, totCol));return 0;
}

  

 

转载于:https://www.cnblogs.com/headboy2002/p/9631719.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/365766.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

js 停止事件冒泡 阻止浏览器的默认行为

在前端开发工作中&#xff0c;由于浏览器兼容性等问题&#xff0c;我们会经常用到“停止事件冒泡”和“阻止浏览器默认行为”。 浏览器默认行为&#xff1a; 在form中按回车键就会提交表单&#xff1b;单击鼠标右键就会弹出context menu. a标签 1..停止事件冒泡 JavaScrip…

魔域传说显示与服务器断开连接,《魔域传说》合服公告

8月2日合服公告亲爱的勇士&#xff0c;为了给大家提供更加优质的游戏体验&#xff0c;《魔域传说》将于2021年8月2日14:00对部分服务器进行合服维护&#xff0c;维护时长预计3小时&#xff0c;维护完成时间视维护情况可能提前或延后&#xff0c;在维护期间将不能登陆服务器&…

python怎么打开程序管理器_Python 进程管理工具 Supervisor 使用教程

因为我的个人网站 restran.net 已经启用&#xff0c;博客园的内容已经不再更新。请访问我的个人网站获取这篇文章的最新内容&#xff0c;Python 进程管理工具 Supervisor 使用教程 Supervisor 是基于 Python 的进程管理工具&#xff0c;只能运行在 Unix-Like 的系统上&#xff…

Hive的伴奏_OURDEN INSTRUMENTALS MIXTAPE Vol.108 “Sober” 伴奏合辑

OURDEN INSTRUMENTALS MIXTAPE Vol.108Sober曲目列表 Track List :Anne Tello – Love Transformation (Prod. By Peter Monk)Blac Youngsta – Left (Prod. By Yung Lan)Bling X – Missing You (Prod. By Phivestarr Productions)BlocBoy JB – Ali (Prod. By Denaro Love)Bl…

命名空间和程序集

命名空间 命名空间是在逻辑上分割代码&#xff0c;程序集是在物理上分割代码。 嵌套命名空间 namespace one { namespace two { } } 通过one.two引用内部嵌套的命名空间的代码。 命名空间不必和程序集同名。 类的可见性 internal 修饰的类&#xff0c;仅能在本程序集中访问。 p…

WebSocket和Java

WebSocket是一项很酷的新技术&#xff0c;它允许浏览器与服务器之间进行实时双向通信&#xff0c;而几乎没有开销。 我在这里想要做的是&#xff0c;提供一个非常简洁但足够全面的概述&#xff0c;以介绍如何开始使用该技术。 因此&#xff0c;从以下几件事开始&#xff1a; 在…

网页顶部进度条-NProcess.js

背景 有些网站&#xff0c;比如github上在查看项目文件夹层级时会在网页顶部出现一个 进度条&#xff0c;虽然是PC端却有一种移动端体验&#xff0c;个人认为可以提升使用体验&#xff0c;经查阅相关资料后&#xff0c;找到一个NProgress.js全站进度条插件 示例 在使用vue开发S…

点击图片放大至原始图片大小

有些时候为了排版的整洁&#xff0c;页面展示的图片不得不都是限定宽高的&#xff0c;如果想要点击图片放大至原始大小进行预览&#xff0c;再次点击回到原来样子&#xff0c;就要用到下面的代码了&#xff1a; var _w parseInt($(window).width());//获取浏览器的宽度$("…

ft服务器设置传输协议,ft服务器设置成主动模式

ft服务器设置成主动模式 内容精选换一换如果您选择使用SFS Turbo实现文件共享存储&#xff0c;此章节操作可跳过&#xff0c;您可以参见《SAP HANA用户指南》中的“格式化磁盘”章节&#xff0c;挂载Backup卷。NFS Server磁盘需要格式化&#xff0c;并挂载到相应的目录后&#…

c语言将字符串按空格分割_以空格作为分隔符的字符串三角形C语言

这是一个独特的三角形&#xff0c;它与所有其他三角形不同&#xff0c;它以这种方式打印由空格分隔的单词。我在寻找的答案不存在于任何其他问题中&#xff0c;已经检查过了。以空格作为分隔符的字符串三角形C语言输出应该是这样的这这是这是这是最好的这是最好的办法这是最好的…

制作逻辑卷快照

逻辑卷快照的功能是将逻辑卷的数据保存备份、以及快速的数据恢复 查看逻辑卷的详细信息&#xff1a;vgdisplay 对vg01卷组的lv01逻辑卷做一个名称为SNAP而大小为150M的逻辑卷快照: lvcreate -L 150M -s -n SNAP /dev/rhcsa/vo 查看逻辑卷和快照的信息: lvs 在逻辑卷中…

使用JPA标准@ViewScoped通过分页,过滤和排序进行Primefaces DataTable延迟加载

Primefaces数据表惰性分页有效&#xff0c;但是在Web上使用Criteria搜索完整示例后&#xff0c;我感到非常沮丧。 所以我混合了来自 http://stackoverflow.com/questions/13972193/how-to-query-data-for-primefaces-datatable-with-lazy-loading-and-pagination http://www.…

mysql text字段导出_Mysql数据库的各种命令:

一、连接MYSQL格式&#xff1a; mysql -h主机地址 -u用户名 -p用户密码1、连接到本机上的MYSQL。 首先打开DOS窗口&#xff0c;然后进入目录mysqlbin&#xff0c;再键入命令mysql -u root -p&#xff0c;回车后提示你输密码. 注意用户名前可以有空格也可以没有空格&#xff0c;…

微信浏览器返回刷新,监听微信浏览器返回事件,网页防复制,移动端禁止图片长按和vivo手机点击img标签放大图片

以下代码都经过iphone7&#xff0c;华为MT7 &#xff0c;谷歌浏览器&#xff0c;微信开发者工具&#xff0c;PC端微信验证。如有bug&#xff0c;还请在评论区留言。 demo链接&#xff1a;https://pan.baidu.com/s/1c35mbjM 密码&#xff1a;5yyf 1.移动端微信浏览器返回刷新…

access数据库为什么一直登陆_为什么要养成用Access数据库保存数据的习惯?

我是宇哥&#xff0c;专门教数据库的&#xff0c;学办公软件的女同学没有不认识我的。一、今天强调一下&#xff1a;为什么要养成用标准数据库保存数据的习惯&#xff5e;其实制造业企业&#xff0c;都更倾向于用Access数据库保存日常数据&#xff0c;尤其是一些高端制造业&…

服务器主板北桥芯片组有哪些,主板芯片组_目前的主板芯片组都有哪些?

目前主流的芯片组有&#xff1a;Intel(英特尔)的、、、。AMD(超微)的、、、。nVidia的、、。芯片组就相当于主板的大脑&#xff0c;主板是什么芯片组决定了主板可以装什么处理器。因为主板芯片分为北桥芯片(离处理器近的)与南桥芯片(离处理器远的)&#xff0c;它们一般是成对出…

快速安装puppeteer (跳过安装Chromium)

npm i --save puppeteer --ignore-scripts 设置镜像下载 npm config set PUPPETEER_DOWNLOAD_HOSThttps://npm.taobao.org/mirrors npm install --save puppeteer 转载于:https://www.cnblogs.com/jso0/p/10336205.html

python地板除与除法的区别_“地板除”还是“取整除”?地板除和天花板除floor division和ceil devision...

上一篇文章知识点太多&#xff0c;我需要一一查看理解。 在运算符 ➡ 算数运算符 ➡ 操作符 ➡ // 整除&#xff08;地板除&#xff09; 3//4 为什么叫地板除&#xff1f; 向下取整除&#xff0c;就是地板除 floor division 向上取整除&#xff0c;就是天花板除&#xff0c;cei…

运行,JUnit! 跑!!!

JUnit与JavaScript和SVN一起是程序员经常开始使用的一些技术&#xff0c;甚至没有读过一篇博客文章&#xff0c;更不用说一本书了。 也许这是一件好事&#xff0c;因为它们看起来足够简单且易于理解&#xff0c;因此我们无需任何手册即可立即使用它们&#xff0c;但这也意味着它…

css3图形绘制

以下几个例子主要是运用了css3中border、bordr-radius、transform、伪元素等属性来完成的&#xff0c;我们先了解下它们的基本原理。 border&#xff1a;简单的来说border语法主要包含&#xff08;border-width、border-style、border-color&#xff09;三个属性。 „ border-t…