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. ...
随机推荐
- Python异步非阻塞IO多路复用Select/Poll/Epoll使用,线程,进程,协程
1.使用select模拟socketserver伪并发处理客户端请求,代码如下: import socket import select sk = socket.socket() sk.bind((' ...
- Linux Shell编程 cut、print命令
cut命令:查找符合条件的列 cut 命令是在文件中提取符合条件的列,虽然 cut 命令用于提取符合条件的列,但是也要一行一行地进行数据提取.也就是说,先要读取文本的第一行数据,在此行中判断是否有符 ...
- MySQL-版本及服务介绍
一.MySQL各版本 1.MySQL产品 下载地址:https://www.mysql.com/downloads/ Oracle MySQL Cloud Service(commercial) 商业 ...
- 修改jpivot源码实现分页
使用jpivot过程中,如果查询到的结果行数超过一个阈值,后面的显示就会丢失,这时需要分页显示. 假设应用中组装的MDX语句已经含有NON EMPTY,把空行直接过滤掉了. 这时需要修改的jpivot ...
- 【bzoj1318】[Spoj744] Longest Permutation(乱搞)
题目传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=1318 这道题的大意是要求一个长度为len,并包含1~len所有数,并使len最大的子区 ...
- 字符串匹配算法BF和KMP总结
背景 来看一道leetcode题目: Implement strStr(). Returns the index of the first occurrence of needle in haysta ...
- Nuxt / Vue.js in TypeScript: Object literal may only specify known properties, but 'components' does not exist in type 'VueClass'
项目背景, Nuxt(vue), TypeScript 生成完项目框架, 添加测试demo页面. 在生成的模板代码中添加layout配置如下: <script lang="ts&quo ...
- Kafka详解四:Kafka的设计思想、理念
问题导读 1.Kafka的设计基本思想是什么?2.Kafka消息转运过程中是如何确保消息的可靠性的? 本节主要从整体角度介绍Kafka的设计思想,其中的每个理念都可以深入研究,以后我可能会发专题文章做 ...
- QT 中一些数学计算函数
QT的一些範例中有出現 qmax, qmin 等 math函式的身影,但我在官方文件中卻找不到與 math函式相關的說明,所以我就把函式的source裡面提供的方法整理條列,並且看看還有哪些 math ...
- vue v-on监听事件
在html或jsp页面中我们总能碰到监听DOM事件来触发javaScript代码,下面我们就简单聊聊Vue.js中的监听事件是怎么处理的. 在vue.js中监听事件是通过v-on指令来实现的,先看一下 ...