zoukankan      html  css  js  c++  java
  • UVA

    题目链接

    题意:求能放进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 }
  • 相关阅读:
    C语言程序设计I—第四周教学
    C语言程序设计I—第三周教学
    C语言程序设计I—第一周教学
    软工实践(四)——热词统计
    软工实践(三)——结对第一次作业(原型设计)
    软工实践(二)——构建之法读后感
    软工实践(一)——目标和规划
    庄子修身养性哲学
    $Matrix-Tree$定理-题目
    $Matrix-Tree$定理-理论
  • 原文地址:https://www.cnblogs.com/asdfsag/p/10367482.html
Copyright © 2011-2022 走看看