[DLX反复覆盖] poj 1084 Square Destroyer

题意:

n*n的矩形阵(n<=5),由2*n*(n+1)根火柴构成,那么当中会有非常多诸如边长为1,为2...为n的正方形,如今能够拿走一些火柴,那么就会有一些正方形被破坏掉。

求在已经拿走一些火柴的情况下。还须要拿走至少多少根火柴能够把全部的正方形都破坏掉。

思路:

对于每一个位置遍历全部可能的边长,确定这个边长下的正方形的边相应的都是数字几,而且把正方形从1開始编号。

然后依据编号,把正方形和数字建边记录方便以下建图。

然后以火柴棍为行,正方形为列,建立dancing link

然后求解。

这里注意的是,须要强行插入某些行。

代码:

#include"stdio.h"
#include"algorithm"
#include"string.h"
#include"iostream"
#include"cmath"
#include"queue"
#include"map"
#include"vector"
#include"string"
using namespace std;
#define RN 70
#define CN 70
#define N 70*70
int fuck[123];
vector<int>edge[123];
struct DLX
{
    int n,m,C;
    int U[N],D[N],L[N],R[N],Row[N],Col[N];
    int H[RN],S[CN],cnt,ans[RN];
    void init(int _n,int _m)
    {
        n=_n;
        m=_m;
        for(int i=0; i<=m; i++)
        {
            S[i]=0;
            U[i]=D[i]=i;
            L[i]=(i==0?m:i-1);
            R[i]=(i==m?

0:i+1);
        }
        C=m;
        for(int i=1; i<=n; i++) H[i]=-1;
    }
    void link(int x,int y)
    {
        C++;
        Row[C]=x;
        Col[C]=y;
        S[y]++;
        U[C]=U[y];
        D[C]=y;
        D[U[y]]=C;
        U[y]=C;
        if(H[x]==-1) H[x]=L[C]=R[C]=C;
        else
        {
            L[C]=L[H[x]];
            R[C]=H[x];
            R[L[H[x]]]=C;
            L[H[x]]=C;
        }
    }
    void del(int x)
    {
        for(int i=D[x]; i!=x; i=D[i])
        {
            R[L[i]]=R[i];
            L[R[i]]=L[i];
        }
    }
    void rec(int x)
    {
        for(int i=U[x]; i!=x; i=U[i])
        {
            R[L[i]]=i;
            L[R[i]]=i;
        }
    }
    int used[CN];
    int h()
    {
        int sum=0;
        for(int i=R[0]; i!=0; i=R[i]) used[i]=0;
        for(int i=R[0]; i!=0; i=R[i])
        {
            if(used[i]==0)
            {
                sum++;
                used[i]=1;
                for(int j=D[i]; j!=i; j=D[j]) for(int k=R[j]; k!=j; k=R[k]) used[Col[k]]=1;
            }
        }
        return sum;
    }
    void dance(int x)
    {
        if(x+h()>=cnt) return ;
        if(R[0]==0)
        {
            cnt=min(cnt,x);
            return ;
        }
        int now=R[0];
        for(int i=R[0]; i!=0; i=R[i])
        {
            if(S[i]<S[now])
                now=i;
        }
        for(int i=D[now]; i!=now; i=D[i])
        {
            del(i);
            for(int j=R[i]; j!=i; j=R[j]) del(j);
            dance(x+1);
            for(int j=L[i]; j!=i; j=L[j]) rec(j);
            rec(i);
        }
        return ;
    }
    void DeleteTrick(int r)  //强行先放入某行。
    {
        if(H[r] == -1) return ;
        for(int i = D[H[r]]; i != H[r]; i = D[i])
        {
            if(H[Row[i]] == i)
            {
                if(R[i] == i)
                {
                    H[Row[i]] = -1;
                }
                else
                {
                    H[Row[i]] = R[i];
                }
            }
            L[R[i]] = L[i];
            R[L[i]] = R[i];
        }

        for(int i = R[H[r]]; i != H[r]; i = R[i])
        {
            for(int j = D[i]; j != i; j = D[j])
            {
                if(H[Row[j]] == j)
                {
                    if(R[j] == j)
                    {
                        H[Row[j]] = -1;
                    }
                    else
                    {
                        H[Row[j]] = R[j];
                    }
                }
                L[R[j]] = L[j];
                R[L[j]] = R[j];
            }
        }
    }
} dlx;
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=0; i<m; i++) scanf("%d",&fuck[i]);
        for(int i=0; i<=70; i++) edge[i].clear();
        int sum=0;
        for(int i=1; i<=n; i++)
        {
            for(int j=1; j<=n; j++)
            {
                int num=(i-1)*(n+n+1)+j;
                int lit=min(n-i+1,n-j+1);
                for(int k=1; k<=lit; k++)
                {
                    sum++;
                    int up,down,left,right;
                    up=num;
                    left=num+n;
                    right=left+k;
                    down=up+k*(n+n+1);
                    for(int o=0; o<k; o++)
                    {
                        edge[up+o].push_back(sum);
                        edge[left+o*(n+n+1)].push_back(sum);
                        edge[right+o*(n+n+1)].push_back(sum);
                        edge[down+o].push_back(sum);
                    }
                }
            }
        }
        dlx.init(2*n*(n+1),sum);

        for(int i=1; i<=2*n*(n+1); i++)
        {
            for(int j=0; j<(int)edge[i].size(); j++) dlx.link(i,edge[i][j]);
        }
        int fff[123];
        memset(fff,0,sizeof(fff));
        //for(int j=0; j<(int)edge[1].size(); j++) printf("%d ",edge[1][j]);
        //puts("");
        for(int i=0; i<m; i++)
        {
            dlx.DeleteTrick(fuck[i]);
        }
        dlx.cnt=999;
        dlx.dance(0);
        printf("%d\n",dlx.cnt);
    }
    return 0;
}
/*
4
4 10
1 2 3 4 5 6 7 8 9 10
*/
时间: 2024-11-09 00:17:56

[DLX反复覆盖] poj 1084 Square Destroyer的相关文章

[DLX重复覆盖] poj 1084 Square Destroyer

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

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

POJ 1084 Square Destroyer【舞蹈链】【重复覆盖】

建模很容易就能说清楚,但我一直想不出来. 要问为什么的话可能是因为这题要先预处理出来所有正方形,而我没做过要预处理的舞蹈链的题.所以想不到. 那就是预处理出来所有正方形,用一个long long来表示一个正方形,这个正方形有没有包含id这条边就用 (1<<id)&num判断.那怎么预处理所有正方形呢,枚举边长1-n的正方形,然后再枚举这个正方形左上方的顶点就能做出来. 然后就能建模了,火柴是行,所有按现有火柴能拼出来的正方形是列,与其说是精准覆盖倒也可以说是全部破坏. http://e

FZU 1686 神龙的难题 DLX反复覆盖

DLX反复覆盖: 须要一个A*函数剪支 Problem 1686 神龙的难题 Accept: 462    Submit: 1401 Time Limit: 1000 mSec    Memory Limit : 32768 KB  Problem Description 这是个剑与魔法的世界.英雄和魔物同在,动荡和安定并存.但总的来说,库尔特王国是个安宁的国家,人民安居乐业,魔物也比較少.可是.总有一些魔物不时会进入城市附近,干扰人民的生活.就要有一些人出来守护居民们不被魔物侵害.魔法使艾米莉

HDU 5046 Airport(DLX反复覆盖)

HDU 5046 Airport 题目链接 题意:给定一些机场.要求选出K个机场,使得其它机场到其它机场的最大值最小 思路:二分+DLX反复覆盖去推断就可以 代码: #include <cstdio> #include <cstring> using namespace std; const int MAXNODE = 4005; const int MAXM = 65; const int MAXN = 65; const int INF = 0x3f3f3f3f; int K;

[DLX反复覆盖] hdu 2828 Lamp

题意: 有N个灯M个开关 每一个灯的ON和OFF状态都能控制一个灯是否亮 给出N行,代表对于每一个灯 哪些开关的哪个状态能够使得第i个灯亮 思路: 这里须要注意一个问题 假设开关1的ON 状态和开关2的ON状态能使得1号灯亮 那么开关1.2同一时候处于ON的时候 1号灯也是亮的.意思就是仅仅要有一个开关使得灯亮,灯就亮了. 简单的DLX 反复覆盖 行为每一个开关的两个状态2*m行,列为n个灯 在搜索的同一时候标记一下哪个开关被用过了 那么还有一个状态也不能用了 代码: #include"stdi

【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根木棍.首先可以预处理分别对正方形和木棍进行编号,进而预处理破坏每根木棍可以

POJ 3047 Sudoku DLX精确覆盖

DLX精确覆盖.....模版题 Sudoku Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 8336   Accepted: 2945 Description In the game of Sudoku, you are given a large 9 × 9 grid divided into smaller 3 × 3 subgrids. For example, . 2 7 3 8 . . 1 . . 1 . .