UVA - 1602 Lattice Animals (暴力+同构判定)

Posted asdfsag

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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
",ans);
 98     }
 99     return 0;
100 }

 

以上是关于UVA - 1602 Lattice Animals (暴力+同构判定)的主要内容,如果未能解决你的问题,请参考以下文章

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

例题 7-14 UVA-1602Lattice Animals

UVA - 1602 Lattice Animals (暴力+同构判定)

UVA 11768 - Lattice Point or Not(数论)

UVA - 11768 Lattice Point or Not (扩展欧几里得)

UVa 1602 网格动物(回溯)