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;
}

原文地址:https://www.cnblogs.com/ZhenghangHu/p/9716624.html

时间: 2024-11-18 07:09:09

POJ 1084 Square Destroyer【舞蹈链】【重复覆盖】的相关文章

poj 1084 Square Destroyer dlx解重复覆盖

分析: 将问题转化为重复覆盖问题,DancingLink解决. 代码: //poj 1084 //sep9 #include <iostream> using namespace std; const int maxN=10024; const int maxL=128; int L[maxN],R[maxN],U[maxN],D[maxN]; int C[maxN],H[maxN]; int S[maxN],A[maxN],X[maxN]; bool makeup[maxL][maxL];

(中等) POJ 1084 Square Destroyer , DLX+可重复覆盖。

Description The left figure below shows a complete 3*3 grid made with 2*(3*4) (=24) matchsticks. The lengths of all matchsticks are one. You can find many squares of different sizes in the grid. The size of a square is the length of its side. In the

[DLX重复覆盖] poj 1084 Square Destroyer

题意: n*n的矩形阵(n<=5),由2*n*(n+1)根火柴构成,那么其中会有很多诸如边长为1,为2...为n的正方形,现在可以拿走一些火柴,那么就会有一些正方形被破坏掉. 求在已经拿走一些火柴的情况下,还需要拿走至少多少根火柴可以把所有的正方形都破坏掉. 思路: 对于每个位置遍历所有可能的边长,确定这个边长下的正方形的边对应的都是数字几,并且把正方形从1开始编号. 然后根据编号,把正方形和数字建边记录方便下面建图. 然后以火柴棍为行,正方形为列,建立dancing link 然后求解. 这里

[DLX反复覆盖] poj 1084 Square Destroyer

题意: n*n的矩形阵(n<=5),由2*n*(n+1)根火柴构成,那么当中会有非常多诸如边长为1,为2...为n的正方形,如今能够拿走一些火柴,那么就会有一些正方形被破坏掉. 求在已经拿走一些火柴的情况下.还须要拿走至少多少根火柴能够把全部的正方形都破坏掉. 思路: 对于每一个位置遍历全部可能的边长,确定这个边长下的正方形的边相应的都是数字几,而且把正方形从1開始编号. 然后依据编号,把正方形和数字建边记录方便以下建图. 然后以火柴棍为行,正方形为列,建立dancing link 然后求解.

【POJ】1084 Square Destroyer

1. 题目描述由$n \times n, n \in [1, 5]$的正方形由$2 \times n \times (n+1)$根木棍组成,可能已经有些木棍被破坏,求至少还需破坏多少木根,可以使得不存在任何正方形?2. 基本思路这是一道非常有趣的题目,可以使用IDA*解也可以用DLX解.可以试试5 0这组数据比较两者的性能差异.(1) IDA*使用IDA*处理,是因为最后的解的范围一定不是很大,因为数据很小.至多也就60根木棍.首先可以预处理分别对正方形和木棍进行编号,进而预处理破坏每根木棍可以

HDU 2828 舞蹈链可重复覆盖

点击打开链接 题意:给n个灯,每个灯能保持亮的状态的条件给出,最后问能否将所有的灯都保持亮的状态,能的话输出每个开关的状态 思路:明显的舞蹈链可重复覆盖嘛,列为n个灯,然后行为每个开关开还是关,所以行要有2*m行,注意的是在跑舞蹈链的时候,每一个开关只能有开或关的状态,所以我们要判断一下它对应的状态是否走过 #include <vector> #include <stdio.h> #include <string.h> #include <stdlib.h>

HDU 2295 舞蹈链可重复覆盖+二分

点击打开链接 题意:给了n个点和m个圆心,在用不多于k个圆的情况下,使得所有的点被覆盖,最小的圆半径多大 思路:问最小的什么什么那么用二分准没错,那么二分条件是什么呢,就是用不多于K的圆能否将所有点覆盖,覆盖这部分就是裸的舞蹈链的可重复覆盖,行为m个圆,列为n个点,然后求出的最少行小于等于K,则成立,否则不成立 #include <math.h> #include <vector> #include <stdio.h> #include <string.h>

FZU 1686 神龙的难题(重复覆盖问题&amp;舞蹈链)

题目链接:[kuangbin带你飞]专题三 Dancing Links D - 神龙的难题 题意 Description 这是个剑与魔法的世界.英雄和魔物同在,动荡和安定并存.但总的来说,库尔特王国是个安宁的国家,人民安居乐业,魔物也比较少.但是.总有一些魔物不时会进入城市附近,干扰人民的生活.就要有一些人出来守护居民们不被魔物侵害.魔法使艾米莉就是这样的一个人.她骑着她的坐骑,神龙米格拉一起消灭干扰人类生存的魔物,维护王国的安定.艾米莉希望能够在损伤最小的前提下完成任务.每次战斗前,她都用时间

HDU 3663 舞蹈链之不可重复覆盖

点击打开链接 题意:给一个无向图,然后n个城市的供电范围,每个现在要求每一个城市的D天都可以有电,对于城市A发电,那么与它相邻的所有城市都会有电,但是问题是每个城市一天内只可以被供电一次,否则会坏掉,并且每个城市的供电天数有范围而且每个城市只能开启开关一次,之后不能在使用,也就是说城市A的供电时间必须是连续的,还有就是可以不用这个城市 思路:因为每个城市一天只能被供电一次,那么就是不可重复覆盖的舞蹈链模型了,那么考虑的就是把什么作为列和行了,很明显这道题就是N*D+N作为列,N*D是n个城市的D