POJ_1084_SquareDestroyer(DancingLinksX重复覆盖)

来源:互联网 发布:c语言入门经典 编辑:程序博客网 时间:2024/05/01 01:26

Square Destroyer
Time Limit: 1000MS Memory Limit: 10000KTotal Submissions: 3642 Accepted: 1577

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.

Input

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.

Output

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.

Sample Input

22033 12 17 23

Sample Output

33

Source

Taejon 2001

DancingLinksX重复覆盖题目


题意给出一个火柴码成的矩阵(类似于矩阵)

然后其中某些火柴是没有的

问至少再拿走多少可以使所有的方形破坏掉


做法

火柴作为行,方形作为列

这题主要麻烦的地方就在于要把火柴对应到方形去

于是想了好久的对应关系

火柴分布如下

/*1 12 3 42 1  23  4  5 6  78  9  10 11 123  1  2  34  5  6  7  8  9 1011 12 13 14 15 16 1718 19 20 21 22 23 244  1  2  3  45  6  7  8  9 10 11 12 1314 15 16 17 18 19 20 21 2223 24 25 26 27 28 29 30 3132 33 34 35 36 37 38 39 405  1  2  3  4  56  7  8  9  10 11 12 13 14 15 1617 18 19 20 21 22 23 24 25 26 2728 29 30 31 32 33 34 35 36 37 3839 40 41 42 43 44 45 46 47 48 4950 51 52 53 54 55 56 57 58 59 60*/


用init初始化了那样一个矩阵

剩下的就好办了

跑模板即可……


#include <iostream>#include <stdio.h>#include <string.h>using namespace std;const int MN=65;//最多60根火柴const int MM=1+2*2+3*3+4*4+5*5+5;//方形数量const int MNN=MN*MM+MM; //最大点数struct DLX{    int n,m,si;//n行数m列数si目前有的节点数    //十字链表组成部分    int U[MNN],D[MNN],L[MNN],R[MNN],Row[MNN],Col[MNN];    //第i个结点的U向上指针D下L左R右,所在位置Row行Col列    int H[MN],S[MM]; //记录行的选择情况和列的覆盖情况    int ansd,ans[MN];  //ansd为最值    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;        si=m;                 //目前用了前0~m个结点        for(int i=1;i<=n;i++)            H[i]=-1;    }    void link(int r,int c)    //插入点(r,c)    {        ++S[Col[++si]=c];     //si++;Col[si]=c;S[c]++;        Row[si]=r;        D[si]=D[c];        U[D[c]]=si;        U[si]=c;        D[c]=si;        if(H[r]<0)            H[r]=L[si]=R[si]=si;        else        {            R[si]=R[H[r]];            L[R[H[r]]]=si;            L[si]=H[r];            R[H[r]]=si;        }    }    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;    }    bool v[MNN];    int h() //估值    {        int ret=0;        for(int c=R[0];c!=0;c=R[c])            v[c]=1;        for(int c=R[0];c!=0;c=R[c])            if(v[c])            {                ret++;                v[c]=0;                for(int i=D[c];i!=c;i=D[i])                    for(int j=R[i];j!=i;j=R[j])                        v[Col[j]]=0;            }        return ret;    }    void dance(int d)    {        if(d+h()>=ansd)  //利用A*优化            return;        if(R[0]==0)        {            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);            dance(d+1);            for(int j = L[i];j != i;j = L[j])                resume(j);            resume(i);        }    }}dlx;int match[6][MN][MM];//矩阵大小,火柴标号,对应小框子int nsq[6];//方格多少void init(){    for(int ii=1;ii<=5;ii++)  //总方格边长    {        int cnt=0;        for(int jj=1;jj<=ii;jj++)//小方格大小        {            for(int i=1;i<=ii+1-jj;i++)//起点横坐标                for(int j=0;j<ii+1-jj;j++)//起点纵坐标                {                    cnt++;                    for(int k=0;k<jj;k++)       //上边                        match[ii][i+j*(2*ii+1)+k][++match[ii][i+j*(2*ii+1)+k][0]]=cnt;                    for(int k=0;k<jj;k++)       //下边                        match[ii][i+(j+jj)*(2*ii+1)+k][++match[ii][i+(j+jj)*(2*ii+1)+k][0]]=cnt;                    for(int k=0;k<jj;k++)       //左边                        match[ii][i+ii+(j+k)*(2*ii+1)][++match[ii][i+ii+(j+k)*(2*ii+1)][0]]=cnt;                    for(int k=0;k<jj;k++)       //右边                        match[ii][i+ii+jj+(j+k)*(2*ii+1)][++match[ii][i+ii+jj+(j+k)*(2*ii+1)][0]]=cnt;                }        }        nsq[ii]=cnt;    }}int isu[MM];int ma[MM];int main(){    int t,n,k;    scanf("%d",&t);    init();    while(t--)    {        scanf("%d%d",&n,&k);        int nu;        memset(isu,0,sizeof(isu));        memset(ma,0,sizeof(ma));        for(int i=1;i<=k;i++)        {            scanf("%d",&nu);            for(int j=1;j<=match[n][nu][0];j++)                isu[match[n][nu][j]]=1;        }        int nisu=0;           //去掉无用的行        for(int i=1;i<=nsq[n];i++)            if(!isu[i])                ma[i]=++nisu;        dlx.init(2*n*(n+1),nisu);        for(int i=1;i<=2*n*(n+1);i++)        {            for(int j=1;j<=match[n][i][0];j++)                if(ma[match[n][i][j]])                    dlx.link(i,ma[match[n][i][j]]);        }        dlx.ansd=1e5;        dlx.dance(0);        printf("%d\n",dlx.ansd);    }    return 0;}


0 0
原创粉丝点击