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就过了)

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 typedef long long ll;
  4 const int N=10+2,inf=0x3f3f3f3f;
  5 const int dx[]= {0,0,-1,1};
  6 const int dy[]= {-1,1,0,0};
  7 //格点
  8 struct P {
  9     int x,y;
 10     bool operator==(const P& b)const {return x==b.x&&y==b.y;}
 11     bool operator<(const P& b)const {return x!=b.x?x<b.x:y<b.y;}
 12 };
 13 //连通块
 14 struct D {
 15     int n;
 16     P p[N];
 17     D(int _n):n(_n) {}
 18     //字典序比较,重点
 19     bool operator<(const D& b)const {
 20         for(int i=0; i<n; ++i) {
 21             if(p[i]<b.p[i])return 1;
 22             if(b.p[i]<p[i])return 0;
 23         }
 24         return 0;
 25     }
 26     //旋转
 27     D rot() {
 28         D ret(n);
 29         for(int i=0; i<n; ++i)ret.p[i]= {-p[i].y,p[i].x};
 30         return ret;
 31     }
 32     //翻转
 33     D flip() {
 34         D ret(n);
 35         for(int i=0; i<n; ++i)ret.p[i]= {-p[i].x,p[i].y};
 36         return ret;
 37     }
 38     //平移到左上角
 39     D norm() {
 40         D ret=*this;
 41         int dx=inf,dy=inf;
 42         for(int i=0; i<n; ++i)dx=min(dx,ret.p[i].x),dy=min(dy,ret.p[i].y);
 43         for(int i=0; i<n; ++i)ret.p[i].x-=dx,ret.p[i].y-=dy;
 44         sort(ret.p,ret.p+n);
 45         return ret;
 46     }
 47     //字典序最小的同构
 48     D minimum() {
 49         D a=this->norm(),b=a;
 50         for(int i=0; i<2; ++i,b=b.flip())
 51             for(int j=0; j<4; ++j,b=b.rot()) {
 52                 b=b.norm();
 53                 if(b<a)a=b;
 54             }
 55         return a;
 56     }
 57 };
 58 set<D> st[N][N][N];
 59 int n,w,h,ans;
 60
 61 int main() {
 62     D t(1);
 63     t.p[0]= {0,0};
 64     st[1][1][1].insert(t);
 65     for(int _=1; _<10; ++_) {
 66         for(int i=1; i<=10; ++i)
 67             for(int j=i; j<=10; ++j) {
 68                 for(D t:st[_][i][j]) {
 69                     t.n++;
 70                     for(int k=0; k<t.n-1; ++k) {
 71                         for(int f=0; f<4; ++f) {
 72                             t.p[t.n-1]= {t.p[k].x+dx[f],t.p[k].y+dy[f]};
 73                             bool ff=1;
 74                             for(int l=0; l<t.n-1; ++l)if(t.p[t.n-1]==t.p[l]) {ff=0; break;}//防止格点重复
 75                             if(!ff)continue;
 76                             int maxx=~inf,minx=inf,maxy=~inf,miny=inf;
 77                             for(int l=0; l<t.n; ++l) {
 78                                 maxx=max(maxx,t.p[l].x);
 79                                 minx=min(minx,t.p[l].x);
 80                                 maxy=max(maxy,t.p[l].y);
 81                                 miny=min(miny,t.p[l].y);
 82                             }
 83                             int tx=maxx-minx+1,ty=maxy-miny+1;
 84                             if(tx>ty)swap(tx,ty);
 85                             st[_+1][tx][ty].insert(t.minimum());
 86                         }
 87                     }
 88                 }
 89             }
 90     }
 91     while(scanf("%d%d%d",&n,&w,&h)==3) {
 92         ans=0;
 93         if(w>h)swap(w,h);
 94         for(int i=1; i<=w; ++i)
 95             for(int j=1; j<=h; ++j)
 96                 ans+=st[n][i][j].size();
 97         printf("%d\n",ans);
 98     }
 99     return 0;
100 }

原文地址:https://www.cnblogs.com/asdfsag/p/10367482.html

时间: 2024-10-15 13:57:35

UVA - 1602 Lattice Animals (暴力+同构判定)的相关文章

UVA 1602 Lattice Animals解题思路(打表+set)

题目链接 https://vjudge.net/problem/UVA-1602 紫书的一道例题,跟之前的很多题目有很多不同. 本题不像是一般的dfs或bfs这样的搜索套路,而是另一种枚举思路. 题意: 输入n. w. h(1≤n≤10,1≤w,h≤n),求能放在w*h网格里的不同的n连块的个数(平移. 旋转. 翻转后相同的图形算作同一种). 思路: 思路很明确,生成图形后判重,加入重复表或弃掉. 本题的重点就在生成和判重. 我的思路: 连通块的生成:通过维护一个int open[10][10]

uva 1549 - Lattice Point(暴力)

题目链接:uva 1549 - Lattice Point 题目大意:给定圆半径,以原点为圆心,求园内有多少个整数点. 解题思路:首先坐标轴将圆分成4份,所以只要单独考虑每一块的个数乘4再加1即可(原点) #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; const double pi = 4 * atan(1.0);

【DFS】【打表】Lattice Animals

[ZOJ2669]Lattice Animals Time Limit: 5 Seconds      Memory Limit: 32768 KB Lattice animal is a set of connected sites on a lattice. Lattice animals on a square lattice are especially popular subject of study and are also known as polyminoes. Polymino

uva 467 - Synching Signals(暴力+数学)

题目连接:uva 467 - Synching Signals 题目大意:有n个红绿灯,给出红灯的时间t,那么该灯从0时刻开始就以2*t为周期绿黄红三灯交替,时间分别为t-5,5,t.问所这n个等从第一变为有一个灯不为绿灯开始,要多久才能变成所有的灯刚好都为绿灯.时间超过1小时输出unable to synch after one hour. 解题思路:一小时才3600秒,枚举秒数判断即可. #include <cstdio> #include <cstring> #include

uva 618 - Doing Windows(暴力+数学)

题目链接:uva 618 - Doing Windows 题目大意:给出电脑桌面的大小W和H,现在在桌面上有4个窗口,给出窗口的初始大小,问说能不能通过调整各个窗口的大小(长宽比例不能变)使得4个屏幕刚好占满整个屏幕,并且互相不覆盖. 解题思路:其实可以直接暴力出所有情况,不过细节比较多,而且要考虑所有的细节. 我的做法的是先将4个窗口缩小至最小的状态,然后枚举左下角的窗口, 有四种可能 蓝色部分为另外枚举的窗口,3,4种情况要分别保证说长.宽相等,然后S部分就是子问题. 所以用一个二进制数来表

uva 565 - Pizza Anyone?(暴力枚举 + 二进制)

题目:uva 565 - Pizza Anyone?(暴力枚举 + 二进制) 题目大意:题目是说有一个人要帮他的朋友们定批萨,然后每个朋友都有自己的口味要求,问能不能定一个批萨然后满足每个朋友的至少一个要求. 能就输出所定批萨里面加的东西,,输出要求按字典序: 不能就输出:No pizza can satisfy these requests. 解题思路:这题里面有16种材料,每种材料只有取与不取的可能,这样就有 2^16 种( 0 - 2^16 - 1),枚举出每种情况然后在分别看是否能满足每

UVA 11768 - Lattice Point or Not(数论)

UVA 11768 - Lattice Point or Not option=com_onlinejudge&Itemid=8&page=show_problem&category=516&problem=2868&mosmsg=Submission+received+with+ID+13823461" target="_blank" style="">题目链接 题意:给定两个点,构成一条线段.这些点都是十分

uva 12009 - Avaricious Maryanna(暴力)

题目连接:uva 12009 - Avaricious Maryanna 题目大意:给定n,求x,x为n位数,并且x*x的后n位还是x. 解题思路:打个表会发现其实有规律,除了n=1的时候多了0和1,其他都是n-1位的基础上再新增一位数,1位的时候是5,6. #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn = 500; int a[

UVA 10010-- Where&#39;s Waldorf?--暴力串处理

 Where's Waldorf?  Given a m by n grid of letters, ( ), and a list of words, find the location in the grid at which the word can be found. A word matches a straight, uninterrupted line of letters in the grid. A word can match the letters in the grid