ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2019-02-12 23:41:04  阅读:421  来源: 互联网

标签:连通 Animals 黑块 int 1602 同构 st Lattice const


题目链接

题意:求能放进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 }

 

标签:连通,Animals,黑块,int,1602,同构,st,Lattice,const
来源: https://www.cnblogs.com/asdfsag/p/10367482.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有