【21.00%】【vijos P1018】智破连环阵
描述
B国在耗资百亿元之后终于研究出了新式武器——连环阵(Zenith Protected Linked Hybrid Zone)。传说中,连环阵是一种永不停滞的自发性智能武器。但经过A国间谍的侦察发现,连环阵其实是由M个编号为1,2,…,M的独立武器组成的。最初,1号武器发挥着攻击作用,其他武器都处在无敌自卫状态。以后,一旦第i(1<=i< M)号武器被消灭,1秒种以后第i+1号武器就自动从无敌自卫状态变成攻击状态。当第M号武器被消灭以后,这个造价昂贵的连环阵就被摧毁了。
为了彻底打击B国科学家,A国军事部长打算用最廉价的武器——炸弹来消灭连环阵。经过长时间的精密探测,A国科学家们掌握了连环阵中M个武器的平面坐标,然后确定了n个炸弹的平面坐标并且安放了炸弹。每个炸弹持续爆炸时间为5分钟。在引爆时间内,每枚炸弹都可以在瞬间消灭离它平面距离不超过k的、处在攻击状态的B国武器。和连环阵类似,最初a1号炸弹持续引爆5分钟时间,然后a2号炸弹持续引爆5分钟时间,接着a3号炸弹引爆……以此类推,直到连环阵被摧毁。
显然,不同的序列a1、a2、a3…消灭连环阵的效果也不同。好的序列可以在仅使用较少炸弹的情况下就将连环阵摧毁;坏的序列可能在使用完所有炸弹后仍无法将连环阵摧毁。现在,请你决定一个最优序列a1、a2、a3…使得在第ax号炸弹引爆的时间内连环阵被摧毁。这里的x应当尽量小。
格式
输入格式
第一行包含三个整数:M、n和k(1<=M, n<=100,1<=k<=1000),分别表示B国连环阵由M个武器组成,A国有n个炸弹可以使用,炸弹攻击范围为k。以下M行,每行由一对整数xi,yi(0<=xi,yi<=10000)组成,表示第i(1<=i<=M)号武器的平面坐标。再接下来n行,每行由一对整数ui,vi(0<=ui,vi<=10000)组成,表示第i(1<=i<=n)号炸弹的平面坐标。输入数据保证随机、无误、并且必然有解。
输出格式
一行包含一个整数x,表示实际使用的炸弹数。
样例1
样例输入1[复制]
4 3 6
0 6
6 6
6 0
0 0
1 5
0 3
1 1
0 0
样例输出1[复制]
2
限制
各个测试点2秒
来源
NOI2003 Day2 Problem3
【题解】
详细的题解参见IOI2004国家集训队论文 楼天城 《浅谈部分搜索+高效算法在搜索问题中的应用》
在百度文库里就能找到。
这里写一下缩略版的。
首先必然是一个炸弹要炸掉一个连续的武器区间,且炸弹要从第一个武器开始炸。
有可能一个连续的武器区间有多个炸弹能够都炸到。
于是转换成二分图匹配的模型
左边的点是[1..m]分割成的若干区间 右边的n个点则代表炸弹.
设can[i][j][k]表示k号炸弹能否从i号武器连续炸到j号武器
左边的点i和右边的点j有边的条件是can[li][ri][j]为true;
我们要用搜索来获取最少需要的炸弹数
每一层搜索枚举的是一个区间
这个区间要给它找一个匹配,即找一个炸弹来炸它。
当然你要保证这个区间能够被一些炸弹炸到。
因此你又得找一个maxl表示一个区间的上界(能够被炸到的上界);
然后枚举这中间的值。
有时候你还可以修改以前的匹配以获得更大的区间上界。
在搜索之前
用DP搞一个perfect[i]表示重复使用炸弹,i..m号武器最少需要多少个炸弹。
在搜索的时候可以用used+perfect[now] 和 已经获得的ans的关系来剪枝。
然后就是maxl的获取需要用到zd[i][j]表示j号炸弹从i号武器开始能够连续炸到的最大武器编号;
记住可以用求匹配的方法来更换之前的匹配以期获得更大的maxl;
注解写得比较详细点
#include <cstdio>
#include <iostream>
#include <queue>
using namespace std;
const int M = 110;
int m, n, k, zd[M][M], a[M], b[M], perfect[M], ans = 2100000000;
bool can[M][M][M],vis[M];
bool reach[M][M],g[M][M];
queue <int> dl;
struct abc
{
int x, y;
};
abc wuqi[M], zhadan[M];
void input(int &r)
{
r = 0;
char t = getchar();
while (!isdigit(t)) t = getchar();
while (isdigit(t)) r = r * 10 + t - '0', t = getchar();
}
int sqr(int x)
{
return x*x;
}
bool hungary(int x)//执行匈牙利算法给某个区间求一个炸弹的匹配。
{
for (int i = 1;i <= n;i++)
if (g[x][i] && !vis[i])
{
vis[i] = true;
if (b[i] == 0 || hungary(b[i]))
{
b[i] = x;
a[x] = i;
return true;
}
}
return false;
}
void sear_ch(int used, int now)
{
if (used + perfect[now] >= ans)//最优性剪枝
return;
if (now == m + 1)//如果已经把所有的武器都消灭了就记录答案退出
{
ans = used;
return;
}
int maxl = now - 1;//获取区间的上限
for (int i = 1; i <= 100; i++) vis[i] = false;
for (int i = 1;i <= n;i++)//如果之前没有用过这个炸弹来匹配
if (b[i] == 0)//就加入队列中
{
vis[i] = true;
dl.push(i);
}
while (!dl.empty())
{
int x = dl.front();
dl.pop();
if (maxl < zd[now][x])//如果用这个炸弹能够增大区间的上限就增加
maxl = zd[now][x];
for (int i = 1;i <= used;i++)//利用匈牙利算法的思路
if (g[i][x] && !vis[a[i]])//可以更改之前的匹配以期获得更大的区间上限
{//因为g[i][x]所以是可以用这个x来代替那个a[i]炸弹的。
vis[a[i]] = true;
dl.push(a[i]);
}
}
if (maxl == now - 1)//如果无法获得更大的区间上限则退出
return;
int tempa[M], tempb[M];
for (int i = 1; i <= 100; i++)//用于回溯
tempa[i] = a[i], tempb[i] = b[i];
for (int i = 1; i <= 100; i++) vis[i] = false;
used++;//枚举的区间又增加了
for (int i = 1; i <= 100; i++)//可以匹配的炸弹是那些能够从now炸到maxl的炸弹
g[used][i] = can[now][maxl][i];//当然这些匹配之后是可能发生变化的。(即可以修改)
hungary(used);//为这个区间匹配一个炸弹
for (int i = maxl; i >= now; i--)//一定要从区间的上限开始往下枚举
{//这样可以较快求出一个暂时的ans,以便我们用最优性剪枝
for (int j = 1; j <= 100; j++)//这个区间的可以匹配的点是很多的。
g[used][j] = can[now][i][j];//因为now..i <= now..maxl
sear_ch(used, i + 1);//所以can[now][i]里面为true的元素是比can[now][maxl]里为true的元素多的
//因此我们在上面那个宽搜里面可以用那些多出来的炸弹来修改原来的匹配;
}
for (int i = 1; i <= 100; i++)
a[i]=tempa[i], b[i] = tempb[i];
}
int main()
{
//freopen("F:\\rush.txt", "r", stdin);
input(m); input(n); input(k);
for (int i = 1; i <= m; i++)
input(wuqi[i].x), input(wuqi[i].y);
for (int i = 1; i <= n; i++)
input(zhadan[i].x), input(zhadan[i].y);
for (int i = 1; i <= m; i++)
for (int j = 1; j <= n; j++)//reach[i][j]表示j号炸弹是否能炸到i号武器
reach[i][j] = (sqr(wuqi[i].x - zhadan[j].x) + sqr(wuqi[i].y - zhadan[j].y)) <= sqr(k);
for (int i = 1; i <= m; i++)
{
for (int j = 1; j <= n; j++)
can[i][i][j] = reach[i][j];//can[i][j][k]表示k号炸弹是否能连续从i号武器炸到j号武器
for (int j = 1; j <= n; j++)
for (int k = i + 1; k <= m; k++)
can[i][k][j] = can[i][k - 1][j] && reach[k][j];
for (int j = 1; j <= n; j++)
{
zd[i][j] = i-1;//zd[i][j]表示j号炸弹从i号武器开始能够连续炸到的最大武器编号
for (int k = i; k <= m; k++)
if (can[i][k][j])
zd[i][j] = k;
}
}
perfect[m + 1] = 0;//pefect[i]表示i..m这些武器炸掉,在可以重复使用炸弹时需要多少个炸弹。
for (int i = m; i >= 1; i--)
{
int t = i;
for (int j = 1; j <= n; j++)
if (zd[i][j] > t)
t = zd[i][j];
perfect[i] = perfect[t + 1] + 1;
}
sear_ch(0, 1);
printf("%d\n", ans);
return 0;
}
【21.00%】【vijos P1018】智破连环阵的更多相关文章
- luogu P1526 [NOI2003]智破连环阵 搜索+最大匹配+剪枝
LINK:智破连环阵 考试的时候 题意没理解清楚 题目是指一个炸弹爆炸时间结束后再放另一个炸弹 而放完一个炸弹紧接另一个炸弹.题目中存在然后二字. 这样我们可以发现某个炸弹只会炸连续的一段. 但是 由 ...
- 题解-NOI2003 智破连环阵
题面 NOI2003 智破连环阵 有 \(m\) 个靶子 \((ax_j,ay_j)\) 和 \(n\) 个箭塔 \((bx_i,by_i)\).每个箭塔可以射中距离在 \(k\) 以内的靶子.第 \ ...
- bzoj4622 [NOI 2003] 智破连环阵
Description B国在耗资百亿元之后终于研究出了新式武器——连环阵(Zenith Protected Linked Hybrid Zone).传说中,连环阵是一种永不停滞的自发性智能武器.但经 ...
- [luogu1526]智破连环阵
(以下在描述复杂度时,认为$n$和$m$相同,因此一律使用$n$) 称第$i$个炸弹能匹配非空区间$[l,r]$,当且仅当$l$到$r$内所有武器都在$i$攻击范围内,且$r=m$或第$r+1$个武器 ...
- bzoj 4622: [NOI 2003] 智破连环阵【dfs+匈牙利算法】
一个炸弹炸一个区间的武器,想到二分图匹配 但是直接dfs断点显然不行,预处理出dis[i]为i到m的至多值来最优性剪枝,并且标记ok[i][j]为炸弹i可以炸到j武器,mx[i][j]为i炸弹从j武器 ...
- P1526 [NOI2003]智破连环阵
目录 题意描述 算法分析 闲话 初步分析 具体思路 剪枝一 剪枝二 剪枝三 总结一下 代码实现 预处理 剪枝一 剪枝二 剪枝三 二分图匹配 代码综合 结语 又是被楼教主虐的体无完肤的一天 题意描述 在 ...
- 每月最后一周的周六晚上21:00执行任务-crontab
0 21 * * 6 /bin/sh /root/time.sh #“6”代表周六 时间判断脚本如下: #!/bin/bash if [ "$(date -d "+7 days&q ...
- relay 2015-02-05 21:00 27人阅读 评论(0) 收藏
scanf函数是以在输入多个数值数据时,若格式控制串中没有非格式字符作输入数据之间的间隔,则可用空格,TAB或回车作间隔. C编译在碰到空格,TAB,回车或非法数据(如对"%d"输 ...
- bzoj AC倒序
Search GO 说明:输入题号直接进入相应题目,如需搜索含数字的题目,请在关键词前加单引号 Problem ID Title Source AC Submit Y 1000 A+B Problem ...
随机推荐
- Error configuring application listener of class org.springframework.web.context.ContextLoaderListene 标签: tomcat
今天敲完ssm框架,启动tomcat时报了这个错误.如图: SEVERE: Error configuring application listener of class org.springfram ...
- QT 引用之前项目模板导致计算速度严重下降
最近做RRT规划算法,在新建工程中测试时,每一个周期大概花费20MS,但是当我把算法移植到之前写的工程模板中时,计算效率相当低,变为500毫秒.期初是以为代码有问题,然后就逐句查找,发现代码并没有问题 ...
- Kafka Connect HDFS
概述 Kafka 的数据如何传输到HDFS?如果仔细思考,会发现这个问题并不简单. 不妨先想一下这两个问题? 1)为什么要将Kafka的数据传输到HDFS上? 2)为什么不直接写HDFS而要通过Kaf ...
- ffmpeg在iOS的使用 - iFrameExtractor源码解析
http://www.cocoachina.com/ios/20150914/13284.html iFrameExtractor地址:https://github.com/lajos/iFrameE ...
- 机房收费系统之【只允许一个MDI窗体 错误:426】 标签: vb 2014-08-15 10:36 1149人阅读 评论(23)
机房收费系统的主窗体是MDI窗体,为了在这个窗体上添加控件,所以我们在窗体上添加了picture控件,在MDI窗体中,子窗体实际上位于MDIClient里,即子窗体的父窗体就是MDIClient,而放 ...
- Gym - 101962B_Color Changing Sofa
题意:将一个沙发放到一个分成好几个色块(一个字母代表一种颜色)的房间里,要求沙发染成跟所在色块一样的颜色,沙发分成(0,1)两种,0可以染成一种颜色,1可以染成一种颜色(换句话说,沙发最多两种颜色), ...
- jQuery学习笔记之可见性过滤选择器
可见性过滤选择器是根据元素的可见和不可见状态来选择相应的元素. 显示隐藏的例子: <!DOCTYPE html> <html> <head> <script ...
- 模板—FFT
卷积:$C[i]=\sum \limits_{j=0}^{i}A[j]*B[i-j]$可以画图理解一下其实就是交叉相乘的和. 卷积可以看作两个多项式乘积的形式,只不过求出的结果的项数不同. FFT讲解 ...
- 在 windows 安装 Jekyll
本文告诉大家一个简单的方法在 Windows 安装 Jekyll 下载 ps1 文件 首先需要安装 Chocolatey ,这个工具可以快速安装 Jekyll 先下载Chocolatey,如果无法从这 ...
- ListOfOpenSourcePrograms
ListOfOpenSourcePrograms Contents Desktop Applications Communication Engineering Educational Financi ...