POJ 1084 Square Destroyer舞蹈链重复覆盖

Posted zhenghanghu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POJ 1084 Square Destroyer舞蹈链重复覆盖相关的知识,希望对你有一定的参考价值。

建模很容易就能说清楚,但我一直想不出来。

要问为什么的话可能是因为这题要先预处理出来所有正方形,而我没做过要预处理的舞蹈链的题。所以想不到。

那就是预处理出来所有正方形,用一个long long来表示一个正方形,这个正方形有没有包含id这条边就用 (1<<id)&num判断。那怎么预处理所有正方形呢,枚举边长1-n的正方形,然后再枚举这个正方形左上方的顶点就能做出来。

然后就能建模了,火柴是行,所有按现有火柴能拼出来的正方形是列,与其说是精准覆盖倒也可以说是全部破坏。

 

http://exp-blog.com/2018/06/11/pid-113/

读到这篇文章,打算模板还是多写几遍吧。于是这个模板就是自己手写的,debug了一整个下午。最后发现我把 l[size] = l[h[r]]写成了l[size]=R[h[r]]。有点气。。

技术分享图片

再说一下f()函数,加不加都ac了,耗时也差不多。但是有的题还是会卡这点常数。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<iomanip> 
#include<algorithm>
#include<vector>
#define INF 2e9
#define maxnode 5000

using namespace std;

int empty[70];
long long square[200];//这个正方形需要哪些火柴 

struct DLX{
    int n,m,size;
    int up[maxnode],down[maxnode],R[maxnode],l[maxnode];
    int h[70],s[200],row[maxnode],col[maxnode];
    int ansd;
    
    void init(int n1,int m1){
        n=n1; m=m1;
        ansd=-1;
        for(int i=0;i<=m;i++){
            up[i] = down[i] = i;
            l[i] = i-1;
            R[i] = i+1;
            s[i]=0;
        }
        size=m;
        l[0]=m; R[m]=0;
        for(int i=1;i<=n;i++) h[i]=-1;
    }
    
    void link(int r,int c){
        row[ ++size ] = r; col[size]=c;
        s[c]++;
        up[size] = down[c];
        down[size]=c;
        down[up[c]]=size;
        up[c]=size;
        if( h[r]==-1 ) l[size]=R[size]=h[r]=size;
        else{
            l[size]=l[h[r]];
            R[size]=h[r];
            R[l[h[r]]]=size;
            l[h[r]]=size;
        }    
    }
    
    void remove(int c){
        for(int i=down[c];i!=c;i=down[i]){
            R[l[i]] = R[i];
            l[R[i]] = l[i];
        }
    }
    
    void resume(int c){
        for(int i=down[c];i!=c;i=down[i]){
            R[l[i]]=i;
            l[R[i]]=i;
        }
    }
    
    bool vis[200];
    int f(){
        int ret=0;
        for(int i=R[0];i!=0;i=R[i]) vis[i]=true;
        for(int i=R[0];i!=0;i=R[i]){
            if( vis[i] ){
                ret++;
                vis[i]=false;
                for(int j=down[i];j!=i;j=down[j]){
                    for(int k=R[j];k!=j;k=R[k]) vis[ col[k] ]=false;
                }
            }
        }
        return ret;
    }
    
    void dance(int d){
        if( ansd!=-1 && d>=ansd ) return;
        if( R[0]==0 ){
            ansd=d;
            return;
        }
        
        int c=R[0];
        for(int i=R[c];i!=0;i=R[i]){
            if( s[i]<s[c] ) c=i;
        }
        
        for(int i=down[c];i!=c;i=down[i]){
            remove(i);
            for(int j=R[i];j!=i;j=R[j]) remove(j);
            dance(d+1);
            for(int j=R[i];j!=i;j=R[j]) resume(j);
            resume(i);
        }    
        
    }
}dlx;


int main(){
    ios::sync_with_stdio(false);
    int t; cin>>t;
    while(t--){
        memset(empty,0,sizeof(empty));
        int n,k1; cin>>n>>k1;
        for(int i=1;i<=k1;i++){
            int id; cin>>id;
            empty[id]=1;
        }
        
        int cnt=0;//有这么多个正方形 
        for(int i=1;i<=n;i++){//搜索长度为i的正方形 
            for(int j=0;j<=n-i;j++){
                for(int k=0;k<=n-i;k++){
                    //正方形的左上角在(j,k) 
                    //这样构造出来的正方形要哪些火柴
                    long long num=0;
                    bool configure=true;
                    
                    //上边
                    int id=k*(n+n+1)+j;
                    for(int j1=1;j1<=i;j1++){
                        id+=1;
                        if( empty[id] ) configure=false;
                        num+=  (long long)1<<id;
                    }
                    //左边
                    id=k*(n+n+1)+j-n;
                    for(int k1=1;k1<=i;k1++){
                        id+=(n+n+1);
                        if( empty[id] ) configure=false;
                        num+= (long long)1<<id;
                    } 
                    //下边
                    id=(k+i)*(n+n+1)+j;
                    for(int j1=1;j1<=i;j1++){
                        id++;
                        if( empty[id] ) configure=false;
                        num+=  (long long)1<<id;
                    }
                    //右边
                    id=k*(n+n+1)+j+i-n;
                    for(int k1=1;k1<=i;k1++){
                        id+=n+n+1;
                        if( empty[id] ) configure=false;
                        num+= (long long)1<<id;
                    }
                    
                    if( configure ) square[++cnt]=num;
                }
            }
        }
        
        dlx.init(2*n*(n+1),cnt);
        for(int i=1;i<=2*n*(n+1);i++){
            for(int j=1;j<=cnt;j++){
                if( ((long long)1<<i)&square[j] ) dlx.link(i,j);
            }    
        }

        dlx.dance(0);
        cout<<dlx.ansd<<endl;    
    }
    

    return 0;    
}

 

以上是关于POJ 1084 Square Destroyer舞蹈链重复覆盖的主要内容,如果未能解决你的问题,请参考以下文章

[DLX反复覆盖] poj 1084 Square Destroyer

POJ 1084 Square Destroyer舞蹈链重复覆盖

UVA 1603 Square Destroyer

例7-15 UVA-1603Square Destroyer

POJ3251 Big Square水题

POJ 2362 Square 深度优先