给出一个n\times m的01矩阵,以及\(h,w\),表示一次可以把矩阵的一个\(h\times w\)的小矩阵变为全0,问至少要多少次可以把整个矩阵变为全0。\(n,m\le 15\)。

分析

注意到\(n,m\)非常小,我们可以直接暴力搜索。每次都可以把\(h\times w\)的小矩阵变为全0,那么贪心地想,同一个小矩阵肯定不会消两次。所以我们把每个原来为1的格子看成列,每一种覆盖看成行,那么这就是一个重复覆盖的问题。

重复覆盖问题一定要记得加剪枝

代码

#include<cstdio>
#include<cctype>
#include<algorithm>
#include<cstring>
using namespace std;
int read() {
int x=0,f=1;
char c=getchar();
for (;!isdigit(c);c=getchar()) if (c=='-') f=-1;
for (;isdigit(c);c=getchar()) x=x*10+c-'0';
return x*f;
}
const int maxn=17;
const int maxm=maxn*maxn;
const int maxp=maxm*maxm;
const int inf=1e9+7;
bool a[maxn][maxn];
int ids[maxn][maxn];
int ans,n,m;
int id(int x,int y) {
return (x-1)*m+y;
}
struct node {
int l,r,u,d,row,col;
};
struct DLX {
node p[maxp];
int tot,last[maxm],size[maxm];
bool tic[maxm];
void clear(int n) {
memset(p,0,sizeof p),memset(last,0,sizeof last),memset(size,0,sizeof size),tot=n;
p[0]=(node){n,1,0,0,0,0};
for (int i=1;i<=n;++i) p[i]=(node){i-1,i+1,i,i,0,i},last[i]=i;
p[n].r=0;
}
void build(int row,int a[],int len) {
if (!len) return;
p[++tot]=(node){tot,tot,last[a[1]],p[last[a[1]]].d,row,a[1]};
p[p[tot].d].u=p[p[tot].u].d=last[a[1]]=tot;
++size[p[tot].col];
for (int i=2;i<=len;++i) {
int x=a[i];
p[++tot]=(node){tot-1,p[tot-1].r,last[x],p[last[x]].d,row,x};
p[p[tot].d].u=p[p[tot].u].d=p[p[tot].l].r=p[p[tot].r].l=last[x]=tot;
++size[p[tot].col];
}
}
void del(int c) {
for (int i=p[c].d;i!=c;i=p[i].d) p[p[i].l].r=p[i].r,p[p[i].r].l=p[i].l,--size[p[i].col];
}
void back(int c) {
for (int i=p[c].u;i!=c;i=p[i].u) p[p[i].l].r=p[p[i].r].l=i,++size[p[i].col];
}
int est() {
memset(tic,0,sizeof tic);
int ret=0;
for (int i=p[0].r;i;i=p[i].r) if (!tic[i]) {
++ret;
tic[i]=true;
for (int j=p[i].d;j!=i;j=p[j].d) for (int k=p[j].r;k!=j;k=p[k].r) tic[p[k].col]=true;
}
return ret;
}
void dance(int now) {
if (!p[0].r) {
ans=min(ans,now);
return;
}
if (now+est()>=ans) return;
int first=p[0].r;
for (int i=p[0].r;i;i=p[i].r) if (size[i]<size[first]) first=i;
if (p[first].d==first) return;
for (int i=p[first].d;i!=first;i=p[i].d) {
del(i);
for (int j=p[i].r;j!=i;j=p[j].r) del(j);
dance(now+1);
for (int j=p[i].l;j!=i;j=p[j].l) back(j);
back(i);
}
}
} dlx;
int main() {
#ifndef ONLINE_JUDGE
freopen("test.in","r",stdin);
freopen("my.out","w",stdout);
#endif
while (~scanf("%d%d",&n,&m)) {
ans=inf;
int ts=0;
for (int i=1;i<=n;++i) for (int j=1;j<=m;++j) {
a[i][j]=read();
if (a[i][j]) ids[i][j]=++ts;
}
dlx.clear(ts);
int tn=read(),tm=read();
for (int i=1;i<=n-tn+1;++i) for (int j=1;j<=m-tm+1;++j) {
static int c[maxm];
int tot=0;
for (int x=i;x<i+tn;++x) for (int y=j;y<j+tm;++y) if (a[x][y]) c[++tot]=ids[x][y];
dlx.build(id(i,j),c,tot);
}
dlx.dance(0);
printf("%d\n",ans);
}
return 0;
}

fzu1686-神龙的难题的更多相关文章

  1. FZU1686 神龙的难题 —— Dancing Links 可重复覆盖

    题目链接:https://vjudge.net/problem/FZU-1686 Problem 1686 神龙的难题 Accept: 812    Submit: 2394 Time Limit: ...

  2. FZU1686 神龙的难题 dancing links 重复覆盖

    分析:每次可以打一个小矩阵的怪,然后把每个怪看成一列,然后每个小矩阵看成一行,枚举左上角就行 注:然后注意总共的节点数是新图的行*列的个数,不是原图 #include<cstdio> #i ...

  3. FZU 1686 神龙的难题 (重复覆盖)

    Problem 1686 神龙的难题 Accept: 397    Submit: 1258Time Limit: 1000 mSec    Memory Limit : 32768 KB  Prob ...

  4. FZU 1686 神龙的难题 (DLX)

    神龙的难题 Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Status ...

  5. FZU 1686 神龙的难题(DLX反复覆盖)

    FZU 1686 神龙的难题 pid=1686" target="_blank" style="">题目链接 题意:中文题 思路:每个1看成列, ...

  6. FZU 1686 神龙的难题 DLX反复覆盖

    DLX反复覆盖: 须要一个A*函数剪支 Problem 1686 神龙的难题 Accept: 462    Submit: 1401 Time Limit: 1000 mSec    Memory L ...

  7. [ACM] FZU 1686 神龙的难题 (DLX 反复覆盖)

    Problem 1686 神龙的难题 Accept: 444    Submit: 1365 Time Limit: 1000 mSec    Memory Limit : 32768 KB  Pro ...

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

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

  9. FZU Problem 1686 神龙的难题 重复覆盖

    题目链接 给出大矩形的长宽, 矩形里面有1,0两个值, 给出小矩形的长宽, 求用最少的小矩形覆盖所有的1. 重复覆盖的模板题. #include <iostream> #include & ...

  10. 舞蹈链(DLX)

    舞蹈链(DLX) Tags:搜索 作业部落 评论地址 一.概述 特别特别感谢这位童鞋His blog 舞蹈链是一种优美的搜索,就像下面这样跳舞- 舞蹈链用于解决精确覆盖或者重复覆盖的问题 你可以想象成 ...

随机推荐

  1. Java设计模式(17)——行为模式之观察者模式(Observer)

    一.概述 概念 UML简图 我们根据一个示例得类图来分析角色 角色 抽象主题:保存观察者聚集(集合),管理(增删)观察者 抽象观察者:定义具体观察者的抽象接口,在得到主题通知后更新自己 具体主题:将有 ...

  2. 【SQLSERVER】如何设置权限用户

    一.设置权限用户的意义 SQLSERVER 数据库有两个登录方式,一个是 Windows 身份验证方式 ,另一个是 SQLSERVER 身份验证方式(sa用户): 1, Windows 身份验证方式, ...

  3. DATA 转 16 进制

    // 转 16进制 编码 NSData *data = [NSData dataWithBytes:(const void *)dataOut length:(NSUInteger)dataOutMo ...

  4. python简单的socket 服务器和客户端

    服务器端代码 if "__main__" == __name__: try: sock = socket.socket(socket.AF_INET, socket.SOCK_ST ...

  5. 一个体验好的Windows 任务栏缩略图开发心得

    本文来自网易云社区 作者:孙有军 前言: 对于一个追求极致体验的软件来说,利用好系统的每一点优秀的特性,将会大大提高软件的品质. Windows vista以来任务栏缩略图,及Win + TAB的程序 ...

  6. HIS系统两种收费模式比较:前计费和后计费

    一.药品 a.前计费:审核(临时医嘱)或者分解(长期医嘱)计费 退费处理方式,1)如果是还未发药,则护士站直接退费;2)如果药房已经发药,则护士站发出退费申请,由护士拿着药品去药房退药退费. b.后计 ...

  7. vs找不到lib以及编译的link过程中出现的问题

    1.#pragma comment 程序中已经通过该语句完成lib库的引入,如果再在input里面添加lib库就会报错: 2.要在general的“导入外部库”的设置选项的目录下面添加引用到的lib库 ...

  8. spring java config 初探

    Java Config 注解 spring java config作为同xml配置形式的另一种表达形式,使用的场景越来越多,在新版本的spring boot中 大量使用,今天我们来看下用到的主要注解有 ...

  9. docker创建redis镜像

    pull redis 镜像 创建redis的镜像有几种方式,可以直接从仓库中拉取,也可以采用dockerfile文件自己编译创建. 基于已有的redis镜像,docker可以采用run,或者creat ...

  10. 开关灯问题(C++)

    [问题描述] 假设有 N 盏灯(N 为不大于 5000 的正整数),从 1 到 N 按顺序依次编号,初始时全部处于开启状态:有 M 个人(M 为不大于 N 的正整数)也从 1 到 M 依次编号.第一个 ...