UVA - 1603 Square Destroyer (DLX可重复覆盖+IDA*)
给你一个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*)的更多相关文章
- (中等) POJ 1084 Square Destroyer , DLX+可重复覆盖。
Description The left figure below shows a complete 3*3 grid made with 2*(3*4) (=24) matchsticks. The ...
- UVA 1603 Square Destroyer
题意: 给定一个火柴棒拼成的方格阵,然后去掉一些火柴棒,问至少再去掉几根火柴棒能够让图中一个正方形都没有. 思路: 1. 由于题目中给定了 n 的范围,2 * n * (n + 1) <= 60 ...
- (简单) FZU 1686 神龙的难题 , DLX+可重复覆盖。
Description 这是个剑与魔法的世界.英雄和魔物同在,动荡和安定并存.但总的来说,库尔特王国是个安宁的国家,人民安居乐业,魔物也比较少.但是.总有一些魔物不时会进入城市附近,干扰人民的生活.就 ...
- UVA - 11214 Guarding the Chessboard (可重复覆盖,DLX+IDA*)
题目链接 正解是IDA*+四个方向判重,但由于是个裸的可重复覆盖问题,可以用DLX水过~ 每个格子与放上皇后能干掉的标记连边,跑可重复覆盖DLX.注意要用IDA*来优化,否则会超时. #include ...
- HDU 3957 Street Fighter(搜索、DLX、重复覆盖+精确覆盖)
很久以前就看到的一个经典题,一直没做,今天拿来练手.街霸 给n<=25个角色,每个角色有 1 or 2 个版本(可以理解为普通版以及爆发版),每个角色版本可以KO掉若干人. 问最少选多少个角色( ...
- poj1084Square Destroyer(LDX解重复覆盖)
题目请戳这里 题目大意:给一个n*n的用单位长度的木棍拼起来的网格图,给每个木棍按图示编号,编号范围1~2*n*(n+1).现在已知图中已经去掉了k个木棍,求还要至少去掉几根木棍能使网格图中不存在正方 ...
- (中等) 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 ...
- hdu5064 DLX可重复覆盖+二分
这题题意是 给了n个城市 在其中小于等于k个城市建立机场然后 使得最远的那个离机场的城市距离最短 二分答案 ,我们对于每次的mid 重新建图然后再来一次DLX,每个点可以覆盖的点建立一条联系就ok了 ...
- (中等) HDU 3335 , DLX+重复覆盖。
Description As we know,the fzu AekdyCoin is famous of math,especially in the field of number theory. ...
随机推荐
- 谷歌机器学习速成课程---3降低损失 (Reducing Loss):学习速率
正如之前所述,梯度矢量具有方向和大小.梯度下降法算法用梯度乘以一个称为学习速率(有时也称为步长)的标量,以确定下一个点的位置.例如,如果梯度大小为 2.5,学习速率为 0.01,则梯度下降法算法会选择 ...
- VM and Docker Container
https://www.zhihu.com/question/48174633 在开始讨论前,先抛出一些问题,可先别急着查看答案,讨论的过程可以让答案更有趣,问题如下: Docker 容器有自己的ke ...
- flex 实现图片播放 方案一 图片全部预加载放内存
这种方案,对于web的应用有局限性,在图片量比较多,比较大的时候,就会爆浏览器异常.一般建议轻量级的采用这种方案. <?xml version="1.0" encoding= ...
- Linux软件包管理 RMP包
RPM 包的安装虽然很方便和快捷,但是依赖性实在是很麻烦,尤其是库文件依赖,还要去 rpmfind 网站査找库文件到底属于哪个 RPM 包,从而导致 RPM 包的安装非常烦琐.那么,有没有可以自动解决 ...
- lvds(800*600)
static struct fb_videomode ldb_modedb[] = { 107 107 { 108 + "LDB-SGA", 60, 800, 600, 25132 ...
- linux 无密码登录
环境:Linux 脚本:Python 功能:批量IP,远程执行命令.拷贝文件 运行:./ssh_scp.py iplist.txt 脚本内容: #!/usr/bin/env python# -*- c ...
- cocos2dx打飞机项目笔记五:CCSpriteBatchNode 的使用
在上一节里,在头文件看到 定义了一个 CCSpriteBatchNode* batchNode;,在addEnemy方法里看到 batchNode->addChild(enemy); 新建的敌机 ...
- [RK3288][Android6.0] 调试笔记 --- user版本默认显示开发者选项【转】
本文转载自:https://blog.csdn.net/kris_fei/article/details/70157137 Platform: ROCKCHIPOS: Android 6.0Kerne ...
- QQ空间如何设置被删除的好友不能访问空间
原来一直都很在乎.自己看着办. 经过简单的测试这种方法还是可以的啊,有问题到时候在说吧.理论上无论是否删除好友都可以限制对方访问空间. 旁边还有可以设置不能访问的名单(看仔细点-设置限制名单).
- java格式化输出 printf 例子
import java.util.Date; public class Printf { public static void main(String[] args) { // %s表示输出字符串,也 ...