UVA - 1602 Lattice Animals (暴力+同构判定)
题意:求能放进w*h的网格中的不同的n连通块个数(通过平移/旋转/翻转后相同的算同一种),1<=n<=10,1<=w,h<=n。
刘汝佳的题真是一道比一道让人自闭...QAQ~~
这道题没什么好的办法,Polya定理也毫无用武之地,只能暴力构造出所有可能的连通块,然后用set判重,比较考验基本功。
连通块可以用一个结构体D来表示,D的n代表黑块数量,然后有至多10个点P(x,y),用另一个结构体数组P[N]来表示。
问题的关键在于如何判重。
首先要知道set是通过<运算符来判重的,因此肯定要重载一下<运算符。既然要重载<运算符,那么就需要能比较出两个连通块的大小来。
如何比较两个黑块数量相同的连通块的大小呢?可以类比向量的字典序大小比较法,把所有的黑块按照x从小到大排序,x相同的按y从小到大排序,就可以比较大小了。
但是同构的两个连通块之间是不具有大小关系的,因此要先想办法把同构的连通块弄成统一的样子。
考虑三类等价变换:
1.平移:$(x,y)\leftrightarrow(x+a,y+b)$
2.旋转:$(x,y)\leftrightarrow(-y,x)$
3.翻转:$(x,y)\leftrightarrow(-x,y)$
所有同构的连通块都可以通过以上三类变换相互得到,对于同构的连通块,可以只保留其中字典序最小的。由于通过旋转和翻转能构造出的不同连通块只有8种,因此可以枚举这8中连通块,然后平移到左上角,取其中字典序最小的即可。
注意在比较字典序的时候,正反都要比较一下。(某人因为忘了反着比较而花了两个小时写了一整页代码来debug~~)
然后就没什么特别需要注意的了,设st[i][j][k]为用i个黑块能构造出j*k(j<=k)的异构连通块的集合,递推搞一搞就行了。
代码:(七重for循环,大概是我写过的层数最多的for循环了~~UVA的评测机也很给力,本地要跑300+ms,交上去30ms就过了)
- #include<bits/stdc++.h>
- using namespace std;
- typedef long long ll;
- const int N=+,inf=0x3f3f3f3f;
- const int dx[]= {,,-,};
- const int dy[]= {-,,,};
- //格点
- struct P {
- int x,y;
- bool operator==(const P& b)const {return x==b.x&&y==b.y;}
- bool operator<(const P& b)const {return x!=b.x?x<b.x:y<b.y;}
- };
- //连通块
- struct D {
- int n;
- P p[N];
- D(int _n):n(_n) {}
- //字典序比较,重点
- bool operator<(const D& b)const {
- for(int i=; i<n; ++i) {
- if(p[i]<b.p[i])return ;
- if(b.p[i]<p[i])return ;
- }
- return ;
- }
- //旋转
- D rot() {
- D ret(n);
- for(int i=; i<n; ++i)ret.p[i]= {-p[i].y,p[i].x};
- return ret;
- }
- //翻转
- D flip() {
- D ret(n);
- for(int i=; i<n; ++i)ret.p[i]= {-p[i].x,p[i].y};
- return ret;
- }
- //平移到左上角
- D norm() {
- D ret=*this;
- int dx=inf,dy=inf;
- for(int i=; i<n; ++i)dx=min(dx,ret.p[i].x),dy=min(dy,ret.p[i].y);
- for(int i=; i<n; ++i)ret.p[i].x-=dx,ret.p[i].y-=dy;
- sort(ret.p,ret.p+n);
- return ret;
- }
- //字典序最小的同构
- D minimum() {
- D a=this->norm(),b=a;
- for(int i=; i<; ++i,b=b.flip())
- for(int j=; j<; ++j,b=b.rot()) {
- b=b.norm();
- if(b<a)a=b;
- }
- return a;
- }
- };
- set<D> st[N][N][N];
- int n,w,h,ans;
- int main() {
- D t();
- t.p[]= {,};
- st[][][].insert(t);
- for(int _=; _<; ++_) {
- for(int i=; i<=; ++i)
- for(int j=i; j<=; ++j) {
- for(D t:st[_][i][j]) {
- t.n++;
- for(int k=; k<t.n-; ++k) {
- for(int f=; f<; ++f) {
- t.p[t.n-]= {t.p[k].x+dx[f],t.p[k].y+dy[f]};
- bool ff=;
- for(int l=; l<t.n-; ++l)if(t.p[t.n-]==t.p[l]) {ff=; break;}//防止格点重复
- if(!ff)continue;
- int maxx=~inf,minx=inf,maxy=~inf,miny=inf;
- for(int l=; l<t.n; ++l) {
- maxx=max(maxx,t.p[l].x);
- minx=min(minx,t.p[l].x);
- maxy=max(maxy,t.p[l].y);
- miny=min(miny,t.p[l].y);
- }
- int tx=maxx-minx+,ty=maxy-miny+;
- if(tx>ty)swap(tx,ty);
- st[_+][tx][ty].insert(t.minimum());
- }
- }
- }
- }
- }
- while(scanf("%d%d%d",&n,&w,&h)==) {
- ans=;
- if(w>h)swap(w,h);
- for(int i=; i<=w; ++i)
- for(int j=; j<=h; ++j)
- ans+=st[n][i][j].size();
- printf("%d\n",ans);
- }
- return ;
- }
UVA - 1602 Lattice Animals (暴力+同构判定)的更多相关文章
- UVA 1602 Lattice Animals
题目 输入n.w.h($1\leqslant n \leqslant 10, 1\leqslant w,h \leqslant n$),求能放在w*h网格里的不同的n连块的个数(注意,平移.旋转.翻转 ...
- UVa 1602 Lattice Animals (STL && 生成n连块 && 无方向形状判重)
题意 : 给定一个 w * h 的 矩阵,在矩阵中找不同n个连通块的个数(旋转,翻转,平移算作一种) 分析 : 这题的关键点有两个 ① 生成n连块并且存储起来(因为题目是多测试用例,如果每一次都重新生 ...
- 【DFS】【打表】Lattice Animals
[ZOJ2669]Lattice Animals Time Limit: 5 Seconds Memory Limit: 32768 KB Lattice animal is a set o ...
- UVA 11768 - Lattice Point or Not(数论)
UVA 11768 - Lattice Point or Not option=com_onlinejudge&Itemid=8&page=show_problem&categ ...
- UVA.12716 GCD XOR (暴力枚举 数论GCD)
UVA.12716 GCD XOR (暴力枚举 数论GCD) 题意分析 题意比较简单,求[1,n]范围内的整数队a,b(a<=b)的个数,使得 gcd(a,b) = a XOR b. 前置技能 ...
- UVA.10305 Maximum Product (暴力)
UVA.10305 Maximum Product (暴力) 题意分析 直接枚举起点和重点,然后算出来存到数组里面,sort然后取最大值即可. 代码总览 #include <iostream&g ...
- UVA1602 Lattice Animals 网格动物 (暴力,STL)
多联骨牌的生成办法,维基上只找到固定的骨牌fix,而free的没有找到. 于是只好写个set判重的简单枚举了. 旋转的操作,可以在坐标轴上画个点,以原点为轴心,逆时针旋转90度,新的点的坐标为(-y, ...
- uva 725 Division(暴力模拟)
Division 紫书入门级别的暴力,可我还是写了好长时间 = = [题目链接]uva 725 [题目类型]化简暴力 &题解: 首先要看懂题意,他的意思也就是0~9都只出现一遍,在这2个5位数 ...
- UVA 11080 - Place the Guards(二分图判定)
UVA 11080 - Place the Guards 题目链接 题意:一些城市.之间有道路相连,如今要安放警卫,警卫能看守到当前点周围的边,一条边仅仅能有一个警卫看守,问是否有方案,假设有最少放几 ...
随机推荐
- 正则表达式test match exec search
(1)((2))(3) $1 是第一个括号 $2 是第二个括号 $3 是第二个括号中的括号 $4 是第三个括号 http://www.jb51.net/article/28007. ...
- str字符串、bool类型常用方法总结
字符串拼接 必须是字符串与字符串拼接 print('马化腾'+'马云') print('马化腾' * 10) 将打印10个马化腾 字符串翻转 [ : :-1] 字符串可以加和乘,不能减和乘 input ...
- selenium模块控制浏览器
利用selenium模块控制浏览器 导入selenium模块:from selenium import webdriver browserFirefox = webdriver.Firefox()#打 ...
- I.MX6Q(TQIMX6Q/TQE9)学习笔记——内核启动与文件系统挂载
经过前面的移植,u-boot已经有能力启动内核了,本文主要来看下如何通过之前移植的u-boot来启动内核.如果按照前面的文章完成了LTIB 的编译,那么,Linux的内核应该就会出现rpm/BUILD ...
- Python编程-网络编程进阶(IO复用、Socketserver)
一.认证客户端的链接合法性 如果你想在分布式系统中实现一个简单的客户端链接认证功能,又不像SSL那么复杂,那么利用hmac+加盐的方式来实现. 服务端 from socket import * imp ...
- Sublime Text3 打开文档乱码
一.安装包管理器使用Ctrl+~快捷键或者通过View->Show Console菜单打开命令行,粘贴如下代码 import urllib.request,os; pf = 'Package C ...
- (十三)linux文件系统详解(基于ext2文件系统)【转】
本文转载自:https://blog.csdn.net/FadeFarAway/article/details/53959639 我们知道,一个磁盘可以划分成多个分区,每个分区必须先用格式化工具(例如 ...
- XXL-Job高可用集群搭建
如果XXL-Job admin挂掉就完蛋了,所有任务无法执行 调度中心:管理任务的触发 调度中心如何实现集群? XXL-Job如何实现集群? 底层已经实现好了!文档里面有的 如果想实现Job集群: ...
- margin和text-align以及align
margin和text-align是css样式,align是html的 <style> .test { width: 400px; height: 200px; background: g ...
- java入门了解03
ASSCII表 . 1.final关键字 (1)含义:最终的意思,修饰方法,类,变量 (2)特点: A:修饰类,不能被继承 B:修饰的方法,不能被重载 ...