题目链接

给你一个n*n的由火柴组成的正方形网格,从中预先拿掉一些火柴,问至少还需要拿掉多少火柴才能破坏掉所有的正方形。

看到这道题,我第一反应就是——把每根火柴和它能破坏掉的正方形连边,不就是个裸的DLX了吗?二话不说直接把我以前写过的DLX板子拿了过来。不过这个问题是可重复覆盖而不是精确覆盖,其实只需要在精确覆盖的基础上稍作修改就行了。

建图方法:枚举出网格完整时所有的火柴和正方形,给它们编上号,除了被拿掉的火柴和已经被破坏掉的正方形,其余的所有火柴和它能破坏掉的正方形连边。

注意跑DLX前要先把所有的空列清掉,否则会死循环。

 #include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=,inf=0x3f3f3f3f;
struct D {
int x[],y[];
bool isbound(D& b) {
for(int i=; i<; ++i) {
if(x[i]>b.x[]&&x[i]<b.x[]&&y[i]>b.y[]&&y[i]<b.y[])return ;
if(x[i]<b.x[]||x[i]>b.x[]||y[i]<b.y[]||y[i]>b.y[])return ;
}
return ;
}
} rod[N],sqr[N];
int n,nrod,nsqr,delrod[N],delsqr[N],m;
struct DLX {
static const int N=;
static const int M=;
static const int MX=;
int n,tot,S[M],H[N],vis[M],ans;
int row[MX],col[MX],L[MX],R[MX],U[MX],D[MX];
void init(int _n) {
n=_n;
for(int i=; i<=n; ++i) {
U[i]=D[i]=i;
L[i]=i-,R[i]=i+;
}
L[]=n,R[n]=;
tot=n+;
memset(S,,sizeof S);
memset(H,-,sizeof H);
memset(vis,,sizeof vis);
ans=inf;
}
void link(int r,int c) {
int u=tot++;
S[c]++;
row[u]=r,col[u]=c;
U[u]=U[c],D[u]=c;
U[D[u]]=D[U[u]]=u;
if(!~H[r])H[r]=L[u]=R[u]=u;
else {
R[u]=H[r],L[u]=L[H[r]];
L[R[u]]=R[L[u]]=u;
}
}
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 restore(int c) {
for(int i=U[c]; i!=c; i=U[i])L[R[i]]=R[L[i]]=i;
}
int h() {
int ret=;
for(int c=R[]; c!=; c=R[c])vis[c]=;
for(int c=R[]; c!=; c=R[c])if(vis[c]) {
++ret,vis[c]=;
for(int i=D[c]; i!=c; i=D[i])
for(int j=R[i]; j!=i; j=R[j])vis[col[j]]=;
}
return ret;
}
void check() {
for(int c=; c<=n; ++c)if(!S[c]) {
for(int i=D[c]; i!=c; i=D[i])L[R[i]]=L[i],R[L[i]]=R[i];
L[R[c]]=L[c],R[L[c]]=R[c];
}
}
void dfs(int dep) {
if(R[]==) {ans=dep; return;};
if(dep+h()>ans)return;
int c=R[];
for(int i=R[]; i!=; 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);
dfs(dep+);
for(int j=L[i]; j!=i; j=L[j])restore(j);
restore(i);
}
}
} dlx; int main() {
int T;
for(scanf("%d",&T); T--;) {
scanf("%d",&n);
nrod=nsqr=;
for(int i=; i<=n; ++i) {
for(int j=; j<=n; ++j)if(j+<=n)rod[nrod++]= {i,i,j,j+};
for(int j=; j<=n; ++j)if(i+<=n)rod[nrod++]= {i,i+,j,j};
}
for(int i=; i<=n; ++i)
for(int j=; j<=n; ++j)
for(int w=; w<=n; ++w)
if(i+w<=n&&j+w<=n)sqr[nsqr++]= {i,i+w,j,j+w};
memset(delrod,,sizeof delrod);
memset(delsqr,,sizeof delsqr);
scanf("%d",&m);
while(m--) {
int x;
scanf("%d",&x);
delrod[x-]=;
for(int j=; j<nsqr; ++j)
if(rod[x-].isbound(sqr[j]))delsqr[j]=;
}
dlx.init(nsqr);
for(int i=; i<nrod; ++i)if(!delrod[i])
for(int j=; j<nsqr; ++j)if(!delsqr[j])
if(rod[i].isbound(sqr[j]))
dlx.link(i+,j+);
dlx.check();
dlx.dfs();
printf("%d\n",dlx.ans);
}
return ;
}

以上是普通DLX可重复覆盖的代码,也可以用IDA*优化一下,代码基本一致:

 #include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=;
struct D {
int x[],y[];
bool isbound(D& b) {
for(int i=; i<; ++i) {
if(x[i]>b.x[]&&x[i]<b.x[]&&y[i]>b.y[]&&y[i]<b.y[])return ;
if(x[i]<b.x[]||x[i]>b.x[]||y[i]<b.y[]||y[i]>b.y[])return ;
}
return ;
}
} rod[N],sqr[N];
int n,nrod,nsqr,delrod[N],delsqr[N],m;
struct DLX {
static const int N=;
static const int M=;
static const int MX=;
int n,tot,S[M],H[N],vis[M];
int row[MX],col[MX],L[MX],R[MX],U[MX],D[MX];
void init(int _n) {
n=_n;
for(int i=; i<=n; ++i) {
U[i]=D[i]=i;
L[i]=i-,R[i]=i+;
}
L[]=n,R[n]=;
tot=n+;
memset(S,,sizeof S);
memset(H,-,sizeof H);
memset(vis,,sizeof vis);
}
void link(int r,int c) {
int u=tot++;
S[c]++;
row[u]=r,col[u]=c;
U[u]=U[c],D[u]=c;
U[D[u]]=D[U[u]]=u;
if(!~H[r])H[r]=L[u]=R[u]=u;
else {
R[u]=H[r],L[u]=L[H[r]];
L[R[u]]=R[L[u]]=u;
}
}
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 restore(int c) {
for(int i=U[c]; i!=c; i=U[i])L[R[i]]=R[L[i]]=i;
}
int h() {
int ret=;
for(int c=R[]; c!=; c=R[c])vis[c]=;
for(int c=R[]; c!=; c=R[c])if(vis[c]) {
++ret,vis[c]=;
for(int i=D[c]; i!=c; i=D[i])
for(int j=R[i]; j!=i; j=R[j])vis[col[j]]=;
}
return ret;
}
void check() {
for(int c=; c<=n; ++c)if(!S[c]) {
for(int i=D[c]; i!=c; i=D[i])L[R[i]]=L[i],R[L[i]]=R[i];
L[R[c]]=L[c],R[L[c]]=R[c];
}
}
bool dfs(int dep,int mxd) {
if(R[]==)return ;
if(dep+h()>mxd)return ;
int c=R[];
for(int i=R[]; i!=; 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);
if(dfs(dep+,mxd))return ;
for(int j=L[i]; j!=i; j=L[j])restore(j);
restore(i);
}
return ;
}
int IDAStar() {for(int mxd=;; ++mxd) {if(dfs(,mxd))return mxd;}}
} dlx; int main() {
int T;
for(scanf("%d",&T); T--;) {
scanf("%d",&n);
nrod=nsqr=;
for(int i=; i<=n; ++i) {
for(int j=; j<=n; ++j)if(j+<=n)rod[nrod++]= {i,i,j,j+};
for(int j=; j<=n; ++j)if(i+<=n)rod[nrod++]= {i,i+,j,j};
}
for(int i=; i<=n; ++i)
for(int j=; j<=n; ++j)
for(int w=; w<=n; ++w)
if(i+w<=n&&j+w<=n)sqr[nsqr++]= {i,i+w,j,j+w};
memset(delrod,,sizeof delrod);
memset(delsqr,,sizeof delsqr);
scanf("%d",&m);
while(m--) {
int x;
scanf("%d",&x);
delrod[x-]=;
for(int j=; j<nsqr; ++j)
if(rod[x-].isbound(sqr[j]))delsqr[j]=;
}
dlx.init(nsqr);
for(int i=; i<nrod; ++i)if(!delrod[i])
for(int j=; j<nsqr; ++j)if(!delsqr[j])
if(rod[i].isbound(sqr[j]))
dlx.link(i+,j+);
dlx.check();
printf("%d\n",dlx.IDAStar());
}
return ;
}

感觉对于这种裸的可重复覆盖而言,DLX除了板子代码长了点外就没什么缺点了,直接无脑建图就行了~~

UVA - 1603 Square Destroyer (DLX可重复覆盖+IDA*)的更多相关文章

  1. (中等) POJ 1084 Square Destroyer , DLX+可重复覆盖。

    Description The left figure below shows a complete 3*3 grid made with 2*(3*4) (=24) matchsticks. The ...

  2. UVA 1603 Square Destroyer

    题意: 给定一个火柴棒拼成的方格阵,然后去掉一些火柴棒,问至少再去掉几根火柴棒能够让图中一个正方形都没有. 思路: 1. 由于题目中给定了 n 的范围,2 * n * (n + 1) <= 60 ...

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

    Description 这是个剑与魔法的世界.英雄和魔物同在,动荡和安定并存.但总的来说,库尔特王国是个安宁的国家,人民安居乐业,魔物也比较少.但是.总有一些魔物不时会进入城市附近,干扰人民的生活.就 ...

  4. UVA - 11214 Guarding the Chessboard (可重复覆盖,DLX+IDA*)

    题目链接 正解是IDA*+四个方向判重,但由于是个裸的可重复覆盖问题,可以用DLX水过~ 每个格子与放上皇后能干掉的标记连边,跑可重复覆盖DLX.注意要用IDA*来优化,否则会超时. #include ...

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

    很久以前就看到的一个经典题,一直没做,今天拿来练手.街霸 给n<=25个角色,每个角色有 1 or 2 个版本(可以理解为普通版以及爆发版),每个角色版本可以KO掉若干人. 问最少选多少个角色( ...

  6. poj1084Square Destroyer(LDX解重复覆盖)

    题目请戳这里 题目大意:给一个n*n的用单位长度的木棍拼起来的网格图,给每个木棍按图示编号,编号范围1~2*n*(n+1).现在已知图中已经去掉了k个木棍,求还要至少去掉几根木棍能使网格图中不存在正方 ...

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

    Description The country of jiuye composed by N cites. Each city can be viewed as a point in a two- d ...

  8. hdu5064 DLX可重复覆盖+二分

    这题题意是 给了n个城市 在其中小于等于k个城市建立机场然后 使得最远的那个离机场的城市距离最短 二分答案 ,我们对于每次的mid 重新建图然后再来一次DLX,每个点可以覆盖的点建立一条联系就ok了 ...

  9. (中等) HDU 3335 , DLX+重复覆盖。

    Description As we know,the fzu AekdyCoin is famous of math,especially in the field of number theory. ...

随机推荐

  1. form 表单<input type="button" value="登录" onclick="loginSubmit ()"/> 点击提示 Uncaught TypeError: loginSubmit is not a function

    在网上搜了一堆东东,仔细看了一下,再加上实验,发现原因出在<form>中. <form method="post"> <button type=&qu ...

  2. Centos小脚本(sftp)

    sftp用户创建,改变属组,家目录 #!/bin/python import os,sys class sftp_user(object): def __init__(self,user,passwd ...

  3. docker helloworld

    阿里云镜像: docker官网 docker官方安装文档 配置阿里云镜像后,重启服务,以及检测服务是否正确启动 docker version.info.--help linux帮助命令man ls 镜 ...

  4. 算法寒假实习面试经过之 滴滴(电话一面二面 offer)

    一面:1h 介绍比赛项目. lr与xgb的区别? xgb 为什么不用归一化,onehot? xgb 与 gbdt的区别. 做这些比赛你们的优势在哪,既然全是相同的套路. RCNN的原理, CNN的原理 ...

  5. macOS 简单使用

    在macOS下进行开发,首先要能够熟练的使用macOS系统. 图形界面和触摸板的操作,时间长了自然就会熟悉,也会发现很好用. 关于快捷键有几点注意一下: Windows下好多跟ctrl结合的快捷键(如 ...

  6. 转:USB枚举

  7. python之使用__future__(解决版本不同,不兼容问题)

    Python的新版本会引入新的功能,但是,实际上这些功能在上一个老版本中就已经存在了.要“试用”某一新的特性,就可以通过导入__future__模块的某些功能来实现. 例如,Python 2.7的整数 ...

  8. Django---media静态文件的配置&全局变量

    media 静态文件配置 static 静态文件多用于存放用于渲染前端页面的相关数据,media用于存放客户上传或其他的文件 setting.py 中加入路径 MEDIA_ROOT = ( os.pa ...

  9. PHP自动导入类

    自动require出所需要的类文件,支持PSR系列规范 spl_autoload_register(function ($class) { $classNames = explode('\\',$cl ...

  10. Struts2的<s:date>标签使用详解[转]

    作用:用来格式化显示日期的格式. 它可以用一种你指定的格式来显示 (如:“yyyy-MM-dd”),可以生成通俗易懂的注释(如:in 2 hours,14 minutes),或者用预先定义的一个格式来 ...