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. ...
随机推荐
- XP、win7下Excel 2007多窗口打开Excel的解决方法
http://blog.x6x8.com/?p=330 Win7下的方法(借鉴了XP的方法): 1.先在桌面先建一个txt文件,将下面的代码复制进去 32位WIN7复制下面一行start “Excel ...
- 流量分析系统---echarts模拟迁移中 ,geocoord从后台获取动态数值
由于在echarts的使用手册中说了 {Object} geoCoord (geoCoord是Object类型) ,所以不能用传统的字符串拼接或数组的方式赋值.在后台的controller中用Map& ...
- python中的值传递和引用传递
Python中的变量是没有类型的,我们可以把它看做一个(*void)类型的指针,变量是可以指向任何对象的,而对象才是有类型的. Python中的对象有可变对象(number,string,tuple等 ...
- 0801 RESTAPI设计,DRF 序列化
1.内容回顾 1.restframework serializer(序列化)的简单使用 QuereySet([obj,obj,obj]) --> JSON ...
- RewriteRule ^(.*)$ index.php/$1 [QSA,PT,L] 是什么意思?
<IfModule mod_rewrite.c> Options +FollowSymlinks RewriteEngine On RewriteCond %{REQUEST_FILENA ...
- Android系统--输入系统(三)必备Linux知识_双向通信(scoketpair)
Android系统--输入系统(三)必备Linux知识_双向通信(scoketpair) 引入 1. 进程和APP通信 创建进程 读取.分发 - 进程发送输入事件给APP 进程读取APP回应的事件 输 ...
- Kubernetes 部署Mysql 主从复制集群
Mysql主从参考文章: https://www.jianshu.com/p/509b65e9a4f5 http://blog.51cto.com/ylw6006/2071864 Statefulse ...
- python机器学习——分词
使用jieba库进行分词 安装jieba就不说了,自行百度! import jieba 将标题分词,并转为list seg_list = list(jieba.cut(result.get(" ...
- C#反射第二天
原文:http://blog.csdn.net/zhaoguiqun/article/details/5954720 1.什么是反射Reflection,中文翻译为 反射. 这是.Net中获取 ...
- Neutron新进展|DragonFlow在Mitaka版本中的Roadmap
OpenStack网络在Mitaka版本中将有哪些新变化?1月11日到12日,DragonFlow的PTL——Eran Gampel,Kuryr的PTL——Gal Sagie,和他们的老大从以色列来到 ...