1. 程式人生 > >UVA - 1602 Lattice Animals (暴力+同構判定)

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

http 構造 需要 long pri namespace print 向量 n)

題目鏈接

題意:求能放進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 }

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