您的位置:首页 > 其它

POJ_1084_SquareDestroyer(DancingLinksX重复覆盖)

2016-05-01 00:12 603 查看
Square Destroyer

Time Limit: 1000MSMemory Limit: 10000K
Total Submissions: 3642Accepted: 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
2
2
0
3
3 12 17 23

Sample Output
3
3

Source

Taejon 2001

DancingLinksX重复覆盖题目

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

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

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

做法

火柴作为行,方形作为列

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

于是想了好久的对应关系

火柴分布如下

/*
1
1
2 3
4

2
1 2
3 4 5
6 7
8 9 10
11 12

3
1 2 3
4 5 6 7
8 9 10
11 12 13 14
15 16 17
18 19 20 21
22 23 24

4
1 2 3 4
5 6 7 8 9
10 11 12 13
14 15 16 17 18
19 20 21 22
23 24 25 26 27
28 29 30 31
32 33 34 35 36
37 38 39 40

5
1 2 3 4 5
6 7 8 9 10 11
12 13 14 15 16
17 18 19 20 21 22
23 24 25 26 27
28 29 30 31 32 33 34 35 36 37 38
39 40 41 42 43 44
45 46 47 48 49
50 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
[nu][0];j++)
isu[match
[nu][j]]=1;
}
int nisu=0;           //去掉无用的行
for(int i=1;i<=nsq
;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
[i][0];j++)
if(ma[match
[i][j]])
dlx.link(i,ma[match
[i][j]]);
}
dlx.ansd=1e5;
dlx.dance(0);
printf("%d\n",dlx.ansd);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: