[kuangbin]专题三 Dancing Links Square Destroyer POJ - 1084【重复覆盖】

【题目描述】
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.
左下的3*3的网格有2*(3*4) (=24)根火柴。所有火柴的长度都是1。你可以在网格中找到许多大小不同的方块。正方形的大小是它的边长。在左图所示的网格中,有9个大小为1的、4个大小为2的和1个大小为3的正方形。
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.
整个网格的每个火柴条都有一个唯一的编号,从左到右,从上到下,如左图所示。如果你从完整的网格中拿出一些火柴,那么网格中的一些方块就会被破坏,这将导致一个不完整的3*3网格。右边的图说明了一个不完整的3*3网格,删除了编号12,17和23三根火柴。这个移除会摧毁5个大小为1,3个大小为2,1个大小为3的正方形。因此,不完整的网格没有大小为3的正方形,但仍有4个大小为1和1个大小为2的正方形。
在这里插入图片描述
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.
在输入中,你会得到一个由不超过2n(n+1)跟火柴组成的n*n的网格,其中自然数n<=5,原题面应该是打错了。您的任务是计算出销毁输入n*n网格中所有方格需要拿走的最小火柴数。

【输入】
The input consists of T test cases. The number of test cases (T ) is given in the first line of the input file.
Each test case consists of two lines: The first line contains a natural number n , not greater than 5, which implies you are given a (complete or incomplete) n*n grid as input, and the second line begins with a nonnegative integer k , the number of matchsticks that are missing from the complete n*n grid, followed by k numbers specifying the matchsticks. Note that if k is equal to zero, then the input grid is a complete n*n grid; otherwise, the input grid is an incomplete n*n grid such that the specified k matchsticks are missing from the complete n*n grid.
第一行输入一个T表示测试数据组数。
每组测试数据有2行,第一行包含一个不超过5的整数n表示你将会得到一个(完整或不完整的)n*n的网格,第二行开始一个非负整数k,表示网格中丢失的火柴数量,后面k个数字表示火柴的编号。注意如果k等于0,表示网格是完整的,否则,表示为一个丢失了k根火柴的不完整网格。

【输出】
Print exactly one line for each test case. The line should contain the minimum number of matchsticks that have to be taken out to destroy all the squares in the input grid.
每组测试数据打印一行,包含需要拿走的用来破坏所有正方形的最小的火柴数量。
【样例输入】
2
2
0
3
3 12 17 23

【样例输出】
3
3

题目链接:https://cn.vjudge.net/problem/POJ-1084

DLX重复覆盖问题,难点是如何构造01矩阵,有点小麻烦,所以菜鸡选择手动打表,逃
数据特别水,好像都不存在n==5的情况

丢人代码如下:

#include <iostream>
#include <cstring>
using namespace std;
static const int MAXM=1+4+9+16+25+10;
static const int MAXN=60+10;
static const int MAXNODE=MAXN*MAXM;
struct DLX{
   
    int n,m,size;
    int U[MAXNODE],D[MAXNODE],R[MAXNODE],L[MAXNODE],Row[MAXNODE],Col[MAXNODE];
    int H[MAXN],S[MAXM];
    int ansd,ans[MAXN];
    bool vis[MAXNODE];
    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-1;
            R[i]=i+1;
        }
        R[m]=0;
        L[0]=m;
        size=m;
        for(int i=1;i<=n;i++)
            H[i]=-1;
    }
    void Link(int r,int c)
    {
   
        ++S[Col[++size]=c];
        Row[size]=r;
        D[size]=D[c];
        U[D[c]]=size;
        U[size]=c;
        D[c]=size;
        if(H[r]<0)
            H[r]=L[size]=R[size]=size;
        else
        {
   
            R[size]=R[H[r]];
            L[R[H[r]]]=size;
            L[size]=H[r];
            R[H[r]]=size;
        }
    }
    void remove(int c)
    {
   
        for(int i=D[c];i!=c;i=D[i])
        {
   
            L[R[i]]=L[i];
            R[L[i]]=R[i];
        }
    }
    void resume(int c)
    {
   
        for(int i=U[c];i!=c;i=U[i])
            L[R[i]]=R[L[i]]=i;
    }
    int f()
    {
   
        int res=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])
            {
   
                res++;
                vis[i]=false;
                for(int j=D[i];j!=i;j=D[j])
                    for(int t=R[j];t!=j;t=R[t])
                        vis[Col[t]]=false;
            }
        return res;
    }
    void Dance(int d)
    {
   
        if(d+f()>ansd)
            return;
        if(R[0]==0)
        {
   
            if(d<ansd)
                ansd=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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值