(中等) 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 grid shown in the left figure, there are 9 squares of size one, 4 squares of size two, and 1 square of size three.

  Each matchstick of the complete grid is identified with a unique number which is assigned from left to right and from top to bottom as shown in the left figure. If you take some matchsticks out from the complete grid, then some squares in the grid will be destroyed, which results in an incomplete 3*3 grid. The right figure illustrates an incomplete 3*3 grid after removing three matchsticks numbered with 12, 17 and 23. This removal destroys 5 squares of size one, 3 squares of size two, and 1 square of size three. Consequently, the incomplete grid does not have squares of size three, but still has 4 squares of size one and 1 square of size two. 

  As input, you are given a (complete or incomplete) n*n grid made with no more than 2n(n+1) matchsticks for a natural number 5 <= n . Your task is to compute the minimum number of matchsticks taken 
  out to destroy all the squares existing in the input n*n grid.

  DLX可重复覆盖的问题,让我们去掉几根火柴,然后把所有的正方形都破坏掉。。。

  把每一个正方形都当做是一列,然后每一根火柴当做是一行。

  其中对于列和行的构造是麻烦的地方。。。。。。

  我是枚举每一个正方形,然后枚举这个正方形的每一条边。。。。。。

  

  其次就是Link之前要删除掉几行,这里TLE了N次,因为删除的时候要用到row,而且H[r]在某些情况下也应该改变才对(这里忘记了,导致一些数据循环停不下来。。。。。。)

代码如下:

#include<iostream>
#include<cstring>

using namespace std;

const int INF=10e8;
const int MaxN=70;
const int MaxM=70;
const int MaxNode=MaxN*MaxM;

struct DLX
{
    int L[MaxNode],R[MaxNode],U[MaxNode],D[MaxNode],col[MaxNode],row[MaxNode];
    int S[MaxM],H[MaxN];
    int n,m,size;
    int ans;

    void init(int _n,int _m)
    {
        n=_n;
        m=_m;

        for(int i=0;i<=m;++i)
        {
            U[i]=D[i]=i;
            R[i]=i+1;
            L[i]=i-1;
            row[i]=0;                // !!!

            S[i]=0;
        }

        R[m]=0;
        L[0]=m;

        size=m;
        ans=INF;

        for(int i=0;i<=n;++i)        // !!!
            H[i]=-1;
    }

    void Link(int r,int c)
    {
        col[++size]=c;
        ++S[c];
        row[size]=r;

        U[size]=U[c];
        D[size]=c;
        D[U[c]]=size;
        U[c]=size;

        if(H[r]==-1)
            H[r]=L[size]=R[size]=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=D[c];i!=c;i=D[i])
        {
            R[L[i]]=R[i];
            L[R[i]]=L[i];
        }
    }

    void remove1(int r)
    {
        if(H[r]==-1)
            return;

        for(int i=U[H[r]];i!=H[r];i=U[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=U[i];j!=i;j=U[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];
            }
    }

    void resume(int c)
    {
        for(int i=U[c];i!=c;i=U[i])
            R[L[i]]=L[R[i]]=i;
    }

    bool vis[MaxM];

    int getH()
    {
        int ret=0;

        for(int c=R[0];c!=0;c=R[c])
            vis[c]=1;

        for(int c=R[0];c!=0;c=R[c])
            if(vis[c])
            {
                ++ret;
                vis[c]=0;

                for(int i=D[c];i!=c;i=D[i])
                    for(int j=R[i];j!=i;j=R[j])
                        vis[col[j]]=0;
            }

        return ret;
    }

    void Dance(int d)
    {
        if(d+getH()>=ans)
            return;

        if(R[0]==0)
        {
            if(d<ans)
                ans=d;

            return;
        }

        int c=R[0];

        for(int i=R[0];i!=0;i=R[i])
            if(S[i]<S[c])
                c=i;

        for(int i=D[c];i!=c;i=D[i])
        {
            remove(i);

            for(int j=R[i];j!=i;j=R[j])
                remove(j);

            Dance(d+1);

            for(int j=L[i];j!=i;j=L[j])
                resume(j);

            resume(i);
        }
    }
};

int N;
DLX dlx;
int ans1[6]={0,1,3,6,9,14};

void slove()
{
    dlx.init(2*N*(N+1),N*(N+1)*(2*N+1)/6);

    int t1,t2;
    int cou=0;
    int K,a;

    cin>>K;

    if(K==0)
    {
        cout<<ans1[N]<<endl;
        return;
    }

    for(int i=1;i<=N;++i)
        for(int j=1;j<=(N-i+1)*(N-i+1);++j)
        {
            ++cou;

            t1=(j-1)%(N-i+1)+1+(2*N+1)*((j-1)/(N-i+1));

            for(int k=0;k<i;++k)
            {
                dlx.Link(k+t1,cou);
                dlx.Link((2*N+1)*k+t1+i-1+N+1,cou);
                dlx.Link((2*N+1)*k+t1+N,cou);
                dlx.Link(k+t1+i*(2*N+1),cou);
            }
        }

    for(int i=0;i<K;++i)
    {
        cin>>a;

        dlx.remove1(a);
    }

    dlx.Dance(0);

    if(dlx.ans==INF)
        cout<<0<<endl;
    else
        cout<<dlx.ans<<endl;
}

int main()
{
    ios::sync_with_stdio(false);

    int T;
    cin>>T;

    while(T--)
    {
        cin>>N;

        slove();
    }

    return 0;
}

时间: 2024-11-05 15:50:14

(中等) POJ 1084 Square Destroyer , DLX+可重复覆盖。的相关文章

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【舞蹈链】【重复覆盖】

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

[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 然后求解.

(中等) HDU 5046 Airport ,DLX+可重复覆盖+二分。

Description The country of jiuye composed by N cites. Each city can be viewed as a point in a two- dimensional plane with integer coordinates (x,y). The distance between city i and city j is defined by d ij = |x i - x j| + |y i - y j|. jiuye want to

HDU 5046 Airport(DLX可重复覆盖)

Problem Description The country of jiuye composed by N cites. Each city can be viewed as a point in a two- dimensional plane with integer coordinates (x,y). The distance between city i and city j is defined by dij = |xi - xj| + |yi - yj|. jiuye want

(简单) FZU 1686 神龙的难题 , DLX+可重复覆盖。

Description 这是个剑与魔法的世界.英雄和魔物同在,动荡和安定并存.但总的来说,库尔特王国是个安宁的国家,人民安居乐业,魔物也比较少.但是.总有一些魔物不时会进入城市附近,干扰人民的生活.就要有一些人出来守护居民们不被魔物侵害.魔法使艾米莉就是这样的一个人.她骑着她的坐骑,神龙米格拉一起消灭干扰人类生存的魔物,维护王国的安定.艾米莉希望能够在损伤最小的前提下完成任务.每次战斗前,她都用时间停止魔法停住时间,然后米格拉他就可以发出火球烧死敌人.米格拉想知道,他如何以最快的速度消灭敌人,减

HDU 3335 Divisibility(DLX可重复覆盖)

Problem Description As we know,the fzu AekdyCoin is famous of math,especially in the field of number theory.So,many people call him "the descendant of Chen Jingrun",which brings him a good reputation. AekdyCoin also plays an important role in th

HDU 3957 Street Fighter(搜索、DLX、重复覆盖+精确覆盖)

很久以前就看到的一个经典题,一直没做,今天拿来练手.街霸 给n<=25个角色,每个角色有 1 or 2 个版本(可以理解为普通版以及爆发版),每个角色版本可以KO掉若干人. 问最少选多少个角色(每个角色只能选一次),使得可以KO掉其他所有人(包括所有版本). 典型的DLX.前∑mode[i]列表示被KO的人版本,重复覆盖.后n列表示选了的人,精确覆盖. 即,在精确覆盖满足的前提下,完成重复覆盖,且使所选行最少. 据说这题可以转化成只用一种覆盖,或者是dfs+剪枝.这里就先这样吧. 加了好多注释,