• BZOJ2353 : 矩形压缩


    如果一个矩形$A$包含另一个矩形$B$,那么选矩形$A$显然不优。

    把坐标离散化,给每个矩形一个随机的unsigned long long权值,并把对应范围内每个格子的权值都异或上它。Floodfill找出所有权值相同的四连通格子,如果某个连通块的形状是矩形,那么就是一个可行的矩形,一共$O(n^2)$个。

    为了让面积和最小,将这些矩形按照面积从小到大排序,依次用匈牙利算法匹配输入的$n$个矩形即可,可以用位运算加速匹配的过程。

    时间复杂度$O(frac{n^4}{32})$。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    typedef unsigned long long ull;
    typedef unsigned int U;
    const int N=70,inf=100000;
    int n,m,i,j,ca,cb,a[N],b[N];ull w[N],col[N][N],goal;
    int xl,xr,yl,yr,area,f[N],cnt,ans;
    bool vis[N][N];
    U g[N*N],v;
    struct Rect{
      int x1,y1,x2,y2,area;
      Rect(){}
      Rect(int _x1,int _y1,int _x2,int _y2,int _area){
        x1=_x1;
        y1=_y1;
        x2=_x2;
        y2=_y2;
        area=_area;
      }
    }rect[N],left[N*N];
    inline bool cmp(const Rect&a,const Rect&b){return a.area<b.area;}
    void init(int*a,int&n){
      int m=0,i;
      sort(a+1,a+n+1);
      for(i=1;i<=n;i++)if(i==1||a[i]>a[m])a[++m]=a[i];
      n=m;
    }
    void cov(int A,int B,int C,int D,ull E){
      int i,j;
      for(i=1;i<=ca;i++)if(a[i]>=A&&a[i+1]<=B)for(j=1;j<=cb;j++)if(b[j]>=C&&b[j+1]<=D)col[i][j]^=E;
    }
    void dfs(int x,int y){
      if(x<1||x>ca||y<1||y>cb)return;
      if(col[x][y]!=goal)return;
      if(vis[x][y])return;
      vis[x][y]=1;
      area+=(a[x+1]-a[x])*(b[y+1]-b[y]);
      xl=min(xl,a[x]);
      xr=max(xr,a[x+1]);
      yl=min(yl,b[y]);
      yr=max(yr,b[y+1]);
      dfs(x-1,y);
      dfs(x+1,y);
      dfs(x,y-1);
      dfs(x,y+1);
    }
    inline bool inside(const Rect&A,const Rect&B){
      return A.x1>=B.x1&&A.x2<=B.x2&&A.y1>=B.y1&&A.y2<=B.y2;
    }
    bool find(int x){
      while(1){
        U t=v&g[x];
        if(!t)return 0;
        int y=__builtin_ctz(t);
        v^=1U<<y;
        if(!f[y]||find(f[y]))return f[y]=x,1;
      }
      return 0;
    }
    int main(){
      scanf("%d",&n);
      for(i=1;i<=n;i++)scanf("%d",&rect[i].x1);
      for(i=1;i<=n;i++)scanf("%d",&rect[i].y1);
      for(i=1;i<=n;i++)scanf("%d",&rect[i].x2);
      for(i=1;i<=n;i++)scanf("%d",&rect[i].y2);
      for(i=1;i<=n;i++){
        a[++ca]=rect[i].x1,a[++ca]=rect[i].x2;
        b[++cb]=rect[i].y1,b[++cb]=rect[i].y2;
      }
      init(a,ca);
      init(b,cb);
      ca--,cb--;
      for(i=1;i<=n;i++)w[i]=w[i-1]*233+10007;
      for(i=1;i<=n;i++)cov(rect[i].x1,rect[i].x2,rect[i].y1,rect[i].y2,w[i]);
      for(i=1;i<=ca;i++)for(j=1;j<=cb;j++)if(!vis[i][j]&&col[i][j]){
        xl=inf,xr=-inf;
        yl=inf,yr=-inf;
        area=0;
        goal=col[i][j];
        dfs(i,j);
        if((xr-xl)*(yr-yl)==area)left[++m]=Rect(xl,yl,xr,yr,area);
      }
      sort(left+1,left+m+1,cmp);
      for(i=1;i<=m;i++)for(j=1;j<=n;j++)if(inside(left[i],rect[j]))g[i]|=1U<<(j-1);
      for(i=1;i<=m;i++){
        v=(1U<<n)-1;
        if(find(i))cnt++,ans+=left[i].area;
      }
      if(cnt<n)ans=-1;
      return printf("%d",ans),0;
    }
    

      

  • 相关阅读:
    矩阵学习摘记,欢迎指正
    [poj1363]Rails_模拟_栈
    JLOI2018 记
    [poj3321]Apple Tree_dfs序_树状数组
    [poj3974]Palindrome_Manacher
    [poj1062]昂贵的聘礼_最短路_离散化
    STL:字符串用法详解
    C++ Primer 有感(管理类的指针成员)
    C++ Primer 有感(标准库set类型)
    C++ Primer 有感(标准库pair)
  • 原文地址:https://www.cnblogs.com/clrs97/p/12154237.html
Copyright © 2020-2023  润新知