解题报告2炸弹.docx
- 文档编号:3168542
- 上传时间:2022-11-18
- 格式:DOCX
- 页数:10
- 大小:26.24KB
解题报告2炸弹.docx
《解题报告2炸弹.docx》由会员分享,可在线阅读,更多相关《解题报告2炸弹.docx(10页珍藏版)》请在冰豆网上搜索。
解题报告2炸弹
《蓝猫炸弹》解题报告
1、题目描述
这天,蓝猫2号来到了一个实验室,他正在对一排炸弹进行研究,这些炸弹排在一条直线上。
为了方便,蓝猫2号就把它们的位置用一个数来表示,这个数就是这一个炸弹与最左边炸弹的距离,每一个炸弹i都有一个“威力值”si。
如果蓝猫2号直接引爆了一个炸弹i,那么它的威力就会向直线的两边扩散。
最开始时,这个威力的强度为si,每移动一个单位的距离,威力强度就减1,如果到了某一处,威力强度为0了,这个威力就消失了。
如果在威力没有消失的时候,又遇到了其它的炸弹,那么这一个炸弹也会引爆。
并且威力强度增加了,增加的值就是刚刚引爆的炸弹的“威力值”,并且这个威力强度也继续沿着原来相同的方向扩散。
现在,蓝猫2号想要直接的引爆最多k个炸弹,使得所有引爆的炸弹数最多,当然,已经爆了的炸弹就消失了,再也不会爆了。
它必须等上一次爆炸完全停止后才能进行下一次爆炸,所以,蓝猫2号找到了你,要你为他解决这个问题。
[输入]
输入文件的第一行有两个正整数n,k(1<=n<=10000,1<=k<=100),分别表示炸弹的个数和最多能直接引爆的炸弹数。
第二行有n个数p1,p2……pn,表示这n个炸弹的位置,用它与第一个炸弹的距离来表示,第一个炸弹在最左边,并且有0=p1 第三行有n个数s1,s2,s3……sn,从左到右表示这n个炸弹的威力值,1<=si<=109。 [输出] 仅有一个数,表示最多能引爆的炸弹数(包括直接引爆的和间接引爆的)。 [输入样例] 62 02561113 114222 [输出样例] 5 注: 首先引爆第4个炸弹,这时第1、2、3、4个炸弹都爆了;然后再引爆第5个或者第6个炸弹,总共就引爆了5个炸弹,这已经是最多的了。 2、算法分析 这道题的目标就是确定一个炸弹序列,引爆最多的炸弹。 在这个中间,求出炸弹的引爆范围就是不可避免的了。 但是遗憾的是,当一个炸弹爆炸后,有些炸弹就不能炸了,还有些炸弹虽然能炸,但是引爆的范围会改变了! 总之,有太多的东西随时间改变。 首先不急于去猜测算法,而是考虑在最开始的时候,引爆一个炸弹后爆炸的范围,把这个叫做“引爆范围”,来分析引爆范围的性质。 炸弹i的引爆范围用[Li,Ri]表示,它表示直接引爆i后,Li到Ri的炸弹都爆了,显然有1≤Li≤i≤Ri≤n。 令 ,不难得出Li=max{j|j≤i,Si-Sj-1≤pi-pj-1},Ri=min{j|j≥i,Sj-Si-1≤Pj-Pi}。 来看下面的结论: 1如果i 直观的讲就是,如果炸弹j在炸弹i的右边,并且炸弹j的引爆范围包含了i,那么j的爆炸范围也包含Li。 2如果炸弹i的引爆范围包含炸弹j,而炸弹j的引爆范围不包含炸弹i,那么炸弹i的引爆范围将包含炸弹j的引爆范围。 结论①的证明: 从直观上来讲,当j爆炸到i时而引爆了i,威力强度大于si,而直接引爆i时,威力强度只有si,所以前者向左传播的范围更远。 根据定义来证明有: Sj-Si>pj-pi所以对于kpi-pk,有(Si-Sk)+(Sj-Si)>(pi-pk)+(pj-pi),即Sj-Sk>pj-pk。 由结论①可知,对于R的情况也会得出相似的性质。 结论②都可以根据①得出来。 为了方便,如果炸弹i的引爆范围包含炸弹j,那么就记为e(i,j)。 看到了上面的两个结论后,再来分析一系列直接引爆的炸弹的有什么性质。 如果有两个炸弹i,j满足e(i,j),它们都是直接引爆的,那么可以把这次爆炸序列进行改变。 在所有的直接引爆的炸弹中,找到这样的i,j满足e(i,j),并且i,j两者在爆炸序列中较早的应该尽量的晚,在这个前提下,保证较晚的尽量的早(这样思路就会清晰一些),如果i在j之前直接引爆(这时假设~e(j,i),~表示非,这种情况后面包括了),那么在i引爆之前,必然有若干位于i与j之间的炸弹引爆了才使得直接引爆i时j不会被引爆。 而在i后直接引爆的炸弹里,任意两个x,y都不满足e(x,y),不难证明它们与爆炸顺序无关了。 可以这样改变序列,把在i之前引爆而位于i与j之间的炸弹从引爆序列中删掉。 这时,到了直接引爆i后,j会引爆,这时爆炸的范围显然比直接引爆j的范围大了。 这是不是有利的? 是的,虽然这会引爆后面需要直接引爆的炸弹,但是,由结论①②可知,只要引爆了这样的炸弹,它的效果就会比直接引爆那个炸弹要好,所以这是有利的。 如果j在i的前面,则可以考虑在原来需要引爆j的时候直接的引爆i,这样效果也不比原来的差。 所以上面得到的结论就是: ③: 不会有两个直接引爆的炸弹i,j满足e(i,j)。 这样,问题变成了要求一些区间,使得区间的并最大,并且任意两个直接引爆的炸弹i,j不满足e(i,j),答案就只会与直接引爆的炸弹有关,而与它们的爆炸顺序无关,这样问题就简化了不少。 现在来设计算法,首先必须要求出L,R。 由于求的方法类似,只讨论求L,由于Li=max{j|j 变一下形,有Li=max{j|j 从左往右计算L,现在已经计算到了i,如果有0 计算Li时,只需要从后往前找到第一个w值比不比i的w值小的数。 然后再把表中后面的元素删掉,再把i添到表后。 这个表实际上就是一个栈,不难发现,求出所有的L值只需要O(n)的时间复杂度。 求出了L和R后,就需要考虑选择不多于k个炸弹使得引爆的炸弹数尽量的多。 通过前面的分析,只需要求出一个炸弹的集合S,|S|≤k,并且对于S中任意两个不同元素i,j,e(i,j),e(j,i)都不成立。 由于与顺序无关,所以可以从左到右选择S中的元素,不难发现,如果已经选择了i个炸弹,那么后面的决策只会与最后一个选择的炸弹有关。 于是,得到了一个状态表示: f[i,j]表示选择了不多于i个炸弹,最后一个选择的炸弹是j时最多引爆的炸弹数是多少。 不考虑边界情况,得出了下面的动态规划方程: f[i,j]=max{f[i-1,x]+Rj-Lj+1-|Inter[j]∩Inter[x]|,x 其中Inter[j]表示从Lj到Rj的炸弹集合。 但是,不难发现,上面的动态规划的复杂度是O(kn2),很不令人满意,必须要做优化。 上面的方程中,x需要满足的条件其实就是x Inter[j]∩Inter[x]可以分两种情况,一个是R[x] 既然有两种情况,那么就把方程式中的x分两种情况,放在两个集合X1,X2中,其中X1的x表示Inter[x]与Inter[j]没有交集,X2中的x表示Inter[x]与Inter[j]有交集,为了方便,1..n中其余的数都属于X3,即不在X1和X2中的数。 能不能从左到右枚举j,然后维护这两个集合X1,X2呢? 似乎很难,因为当j增大1时,Lj的变化难以把握,元素可以从X3到X2中,从X2到X1中,也可以从X1到X2,X2到X3,甚至可以从X1到X3,X3到X1,这样维护两个集合,是没有丝毫意义的。 由于上面的变化比较复杂,即使我们加上了若干个堆,线段树之类的高级结构,也很难降低复杂度。 换一个方法,上面造成集合里元素变化如此没有规律的原因是什么? 很大程度上是由于L变化的无规律性,那么,为什么不使L变化有规律一些呢? 这个思路是可以的,具体来说,就是不按j从小往大计算f[i,j],而是按照Lj从小到大计算f[i,j],这样能不能行得通呢? 首先,上面的规划是满足拓扑顺序的,即保证了如果Lx≥Lj,那么在计算j时x一定会在X3中。 由于L是不变小的,所以元素只可能从X2到X1中,不能从X1到X2中。 但是元素在X2与X3中的传递是双向的,如果直接维护两个集合,复杂度也不能降下来。 但是,我们可以用一个数据结构来达到不平常的效果: 线段树。 由于元素在X2与X3的传递是双向的,所以我们干脆不把它们分开。 现在来重新划分集合: (对于当前的j而言) X1={x|Rx X2={x|x X3={x|x≥Lj} 这样,在X1中的元素可以直接计算出方程中的最大值。 在X3的元素对方程没有影响。 虽然在X2中的元素有一些对方程有影响,有一些没有,但是它们有一个很明显的区别,那就是: Rx与j的大小关系。 由于j是定值,所以在X2中的x,只要有Lj≤Rx 而需要计算的x的R值是处在某一段之间的,这意味着,可以利用R为序来建一棵线段树,那么,线段树的关键字是什么? 回到上面的方程,如果x∈X2,那么会有方程: f[i,j]=max{f[i-1,x]+Rj-Rx,x∈X2},由于Rj可以移出来,所以对于X2中的元素x,建树的关键字是f[i-1,x]-Rx,对于每一个元素x,树中x对应的叶子节点保存的就是: max{f[i-1,y]|Ry=x}。 这样,最开始不仅要记录按L值从小到大排序的表,也要计算一个按照R值从小到大排好序的表。 再来总结一下整个算法,首先用O(n)的时间复杂度计算出每一个炸弹的L,R值,然后从f[i-1]到f[i]的转移中,维护一棵树并记下一个最大值max1(不需要记X1,只需要记一个最大的f[i-1,x]就可以了)。 按照j的L值从小到大计算f[i,j],计算过程中,把满足Rx 计算f[i,j]时,在X1中就是max1+Rj-Lj+1,在X2中,满足Rx在Lj到j-1之间的最大的f[i-1,x]-Rx值,然后再加上Rj值。 那么需不需要从树中删除元素呢? 没必要,因为一旦Lj>Rx了,这个x不需要在X2中计算也不会在X2中计算了,整个算法的复杂度是O(knlog2n)。 这个复杂度能够承受了,最大的点(n=10000,k=100)也只需要0.95s(Pentium41.70GHzFreePascalv1.0.6)。 解决问题的思路是: 首先需要分析性质从一个非多项式算法得到一个多项式算法,然后需要利用性质从一个多项式算法得到一个更优的多项式算法。 但是,问题是否就此解决了呢? 算法有没有进一步优化呢? 能不能从O(knlog2n)降到O(kn)呢? 有兴趣的可以继续思考。 [参考文献] 《算法艺术与信息学竞赛》——刘汝佳黄亮著 [讨论] 在与肖天的讨论中否决了O(kn)的算法,只好用O(knlog2n)的了。 [感谢] 肖天、金恺 3、程序 const inputfile='bomb.in'; outputfile='bomb.out'; maxn=100000; type arr=array[0..maxn]oflongint; var n,m,n1: longint; address1,address2,address3,address4,address5,address6: arr; p: arrabsoluteaddress1; f: arrabsoluteaddress1; s: arrabsoluteaddress2; q: arrabsoluteaddress2; f1: arrabsoluteaddress2; totals: arrabsoluteaddress3; listl: arrabsoluteaddress3; left
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 解题 报告 炸弹