题面

NOI2003 智破连环阵

有 \(m\) 个靶子 \((ax_j,ay_j)\) 和 \(n\) 个箭塔 \((bx_i,by_i)\)。每个箭塔可以射中距离在 \(k\) 以内的靶子。第 \(i+1\) 只有第 \(i\) 个靶子被射中时才能被射中。每个箭塔只能用一次,现在可以安排每个箭塔的射击顺序,求最少需要几个箭塔可以射光 \(m\) 靶子。

数据范围:\(1\le m,n\le 100\),\(1\le k\le 1000\),\(1\le ax_j,ay_j,bx_i,by_i\le 10000\)。


蒟蒻语

爆搜神题,可惜题解都很晦涩,蒟蒻因为一个小错误折腾了一个晚上,现在拿到了最优解,于是准备写个逊逊的题解。


蒟蒻解

首先每个箭塔解决一个靶子区间。

所以可以爆搜每个区间和箭塔匹配,这很明显是个二分图匹配。

为了方便处理很多细节,设所有 \(i\) 为箭塔的下标,\(j\) 为靶子的下标。

bool \(con_{i,j}\) 表示箭塔 \(i\) 与靶子 \(j\) 联通。

由于每个箭塔的每个负责区间只需用后缀就可以有解,所以记录 \(nex_{i,j}\) 表示箭塔 \(i\) 在靶子 \(j\) 后面第一个射不到的靶子(即可用射到最右边的靶子下标 \(+1\))。

// 这是一个很显然的递推
R(i,0,n)L(j,0,m) con[i][j]&&(nex[i][j]=max(j+1,nex[i][j+1]));

为了后面 A* 做准备,还可以求出一个 \(mn_j\) 表示打到靶子 \(j\) 的剩余步数下限。

L(j,0,m)R(i,0,n) con[i][j]&&(mn[j]=min(mn[j],mn[nex[i][j]]+1));

然后就可以开始惊心动魄的 Dfs 了。

最直接的方法是先用 \(mn_j\) 来剪枝 A* 一下,然后用 \(nex_{i,j}\) 枚举下一个区间端点,用过的箭塔打个标记,匹配一个没用过的箭塔。

前文说过这是个二分图匹配,所以有个野蛮操作(二分图优化):每次区间找好后,直接匈牙利匹配看看能不能匹配得到箭塔。

这个操作时间复杂度比起原来操作是不增的。

但是这有什么用呢?要配上另一个骚操作:逆序枚举下一个区间开始端点。

由于用了匈牙利后完美匹配概率变高,所以就可以尽早找到优的答案,进一步 A* 剪枝。

然后就结束了,时限 \(2s\) 的题跑得最慢的点 \(4ms\),总时间 \(31ms\)。

注意 Dfs 回溯算法两个坑:回溯不彻底、回溯用了全局变量。


代码

#include <bits/stdc++.h>
using namespace std; //Start
typedef long long ll;
typedef double db;
#define mp(a,b) make_pair((a),(b))
#define x first
#define y second
#define be(a) (a).begin()
#define en(a) (a).end()
#define sz(a) int((a).size())
#define pb(a) push_back(a)
#define R(i,a,b) for(int i=(a),I=(b);i<I;i++)
#define L(i,a,b) for(int i=(b)-1,I=(a)-1;i>I;i--)
const int iinf=0x3f3f3f3f;
const ll linf=0x3f3f3f3f3f3f3f3f; /*
注意: i 是箭塔,j 是靶子,s 是区间
*/ //Data
const int N=1e2;
int m,n,k;
pair<int,int> a[N],b[N];
bitset<N> con[N];
#define f(x) ((x)*(x)) //Dfs
bitset<N> e[N],vis;
int nex[N][N+1],mn[N+1],mat[N],ans;
bool match(int s){ // 匈牙利匹配
R(i,0,n)if(e[s][i]&&!vis[i]){
vis[i]=true;
if(!~mat[i]||match(mat[i]))
return mat[i]=s,true;
}
return false;
}
void dfs(int j,int s){
if(ans<=s+mn[j]) return; //A*
if(j==m) return void(ans=s);
int cmat[N]; copy(mat,mat+n,cmat); // 这里的 cmat 你要是设为全局变量就死了,我在这里死了 2 个小时
L(J,j+1,m+1){
R(i,0,n) con[i][j]&&nex[i][j]>=J&&(e[s][i]=true);
R(i,0,n) vis[i]=false; match(s)?dfs(J,s+1):void();
R(i,0,n) con[i][j]&&nex[i][j]>=J&&(e[s][i]=false); //莫忘回溯
copy(cmat,cmat+n,mat);
}
} //Main
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>m>>n>>k;
R(j,0,m) cin>>a[j].x>>a[j].y;
R(i,0,n) cin>>b[i].x>>b[i].y;
R(i,0,n)R(j,0,m) con[i][j]=(f(a[j].x-b[i].x)+f(a[j].y-b[i].y)<=f(k));
R(i,0,n) fill(nex[i],nex[i]+m+1,-1);
R(i,0,n)L(j,0,m) con[i][j]&&(nex[i][j]=max(j+1,nex[i][j+1]));
R(j,0,m) mn[j]=iinf;
L(j,0,m)R(i,0,n) con[i][j]&&(mn[j]=min(mn[j],mn[nex[i][j]]+1));
fill(mat,mat+n,-1),ans=min(n,m),dfs(0,0);
// 夹杂点骚操作(正确性不保证,仅用来抢最优解:猜测最终 ans<=mn[0]+5),把 ans 的初始值和 mn[0]+5 取 min
cout<<ans<<'\n';
return 0;
}

祝大家学习愉快!

题解-NOI2003 智破连环阵的更多相关文章

  1. luogu P1526 [NOI2003]智破连环阵 搜索+最大匹配+剪枝

    LINK:智破连环阵 考试的时候 题意没理解清楚 题目是指一个炸弹爆炸时间结束后再放另一个炸弹 而放完一个炸弹紧接另一个炸弹.题目中存在然后二字. 这样我们可以发现某个炸弹只会炸连续的一段. 但是 由 ...

  2. P1526 [NOI2003]智破连环阵

    目录 题意描述 算法分析 闲话 初步分析 具体思路 剪枝一 剪枝二 剪枝三 总结一下 代码实现 预处理 剪枝一 剪枝二 剪枝三 二分图匹配 代码综合 结语 又是被楼教主虐的体无完肤的一天 题意描述 在 ...

  3. 【21.00%】【vijos P1018】智破连环阵

    描述 B国在耗资百亿元之后终于研究出了新式武器--连环阵(Zenith Protected Linked Hybrid Zone).传说中,连环阵是一种永不停滞的自发性智能武器.但经过A国间谍的侦察发 ...

  4. bzoj4622 [NOI 2003] 智破连环阵

    Description B国在耗资百亿元之后终于研究出了新式武器——连环阵(Zenith Protected Linked Hybrid Zone).传说中,连环阵是一种永不停滞的自发性智能武器.但经 ...

  5. bzoj 4622: [NOI 2003] 智破连环阵【dfs+匈牙利算法】

    一个炸弹炸一个区间的武器,想到二分图匹配 但是直接dfs断点显然不行,预处理出dis[i]为i到m的至多值来最优性剪枝,并且标记ok[i][j]为炸弹i可以炸到j武器,mx[i][j]为i炸弹从j武器 ...

  6. [luogu1526]智破连环阵

    (以下在描述复杂度时,认为$n$和$m$相同,因此一律使用$n$) 称第$i$个炸弹能匹配非空区间$[l,r]$,当且仅当$l$到$r$内所有武器都在$i$攻击范围内,且$r=m$或第$r+1$个武器 ...

  7. ZJOI2017 Day1

    私のZJOI Day1 2017-3-21 07:52:53 有人在暴力膜 苟-- 富贵 无相忘 ZJOI2017交流群 133135071 如果你足够厉害 如果你足够厉害 如果你足够厉害 其实完全可 ...

  8. 【NOI2003——搜索+二分图匹配优化】

    A 文本编辑器 无旋treap真好看 B 木棒游戏 暴力神仙题 C 数据生成器 树的直径两端点为Y, Z D 智破连环阵 搜索+二分图匹配优化 第一次写欸 列一下 void dfs (int y,in ...

  9. bzoj AC倒序

    Search GO 说明:输入题号直接进入相应题目,如需搜索含数字的题目,请在关键词前加单引号 Problem ID Title Source AC Submit Y 1000 A+B Problem ...

随机推荐

  1. KafkaProducer 发送消息流程

    Kafka 的 Producer 发送消息采用的是异步发送的方式.在消息发送的过程中,涉及到了 两个线程--main 线程和 Sender 线程,以及一个线程共享变量--RecordAccumulat ...

  2. linux之DNS服务

    1.DNS (Domain Name Service 域名解析) DNS是因特网上作为域名和IP地址相互映射的一个分布式数据库,能够使用户更方便的访问互联网而不需要记忆能够直接被机器识别的IP. BI ...

  3. 使用 JavaScript 操作浏览器历史记录 API

    History 是 window 对象中的一个 JavaScript 对象,它包含了关于浏览器会话历史的详细信息.你所访问过的 URL 列表将被像堆栈一样存储起来.浏览器上的返回和前进按钮使用的就是 ...

  4. 通过tuned-adm调整服务器的各种参数

    前言 centos7 服务器上面支持通过tuned进行统一的系统参数调整,以前我们可能会通过修改内核配置文件修改内核参数,通过echo去调整磁盘预读,等等很多调整会分散在各处 而系统实际上是可以通过一 ...

  5. springboot中使用Filter、Interceptor和aop拦截REST服务

    在springboot中使用rest服务时,往往需要对controller层的请求进行拦截或者获取请求数据和返回数据,就需要过滤器.拦截器或者切片. 过滤器(Filter):对HttpServletR ...

  6. 02python开发之基本运算符

    02 python开发之基本运算符 目录 02 python开发之基本运算符 2 基本运算符 2.1 算数运算符 2.1.1 种类 2.1.2 用法 2.2 比较运算符 2.2.1 种类 2.2.2 ...

  7. Tuxera Disk Manager轻松解决硬盘格式转换问题

    生活中经常会遇到硬盘格式转换的问题,很多小伙伴都不知道怎么进行操作,特别是Mac小白们.今天,小编想要给不熟悉Mac系统的小伙伴推荐一款专业且高效的磁盘管理工具--Tuxera NTFS,可以帮助我们 ...

  8. Pypi项目包发布

    前言 用过python的人肯定对pip安装不陌生,pip安装的包的来源都是在Pypi上.为了能随时能使用自己的包,所以尝试一下将自己的包发布到Pypi上. 步骤 一.准备项目 一.创建目录结构 二.准 ...

  9. Java蓝桥杯——排列组合

    排列组合介绍 排列,就是指从给定n个数的元素中取出指定m个数的元素,进行排序. 组合,则是指从给定n个数的元素中仅仅取出指定m个数的元素,不考虑排序. 全排列(permutation) 以数字为例,全 ...

  10. Java蓝桥杯02——第二题集锦:生日蜡烛、星期一、方格计数、猴子分香蕉

    第二题 生日蜡烛(结果填空) 某君从某年开始每年都举办一次生日party,并且每次都要吹熄与年龄相同根数的蜡烛. 现在算起来,他一共吹熄了236根蜡烛. 请问,他从多少岁开始过生日party的? 请填 ...