欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 编程问答 >内容正文

编程问答

信息学奥赛一本通 1322:【例6.4】拦截导弹问题(Noip1999)

发布时间:2025/3/17 编程问答 84 豆豆
生活随笔 收集整理的这篇文章主要介绍了 信息学奥赛一本通 1322:【例6.4】拦截导弹问题(Noip1999) 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

【题目链接】

ybt 1322:【例6.4】拦截导弹问题(Noip1999)
原题有两个问,本题为第2问

【题目考点】

1. 贪心

【解题思路】

hhh表示当前系统可以拦截的最高的高度。
贪心选择:高度小于等于hhh的导弹中高度最高的导弹。
如果当前系统无法再拦截导弹,而且存在未被拦截的导弹,那么增加一个拦截系统,将hhh设为无穷大,继续进行贪心选择。

各导弹高度构成一个数字序列,每个拦截系统拦截的导弹的高度为原序列的不升子序列。该题可以抽象为:求一个数字序列的不升子序列的最少个数。
以下讨论中使用抽象后的概念。

1. 贪心选择性质的证明:

贪心选择:选择小于等于hhh的最大数字,而后将hhh设为该数字。如果不存在,开新的序列,将hhh设为无穷大。

该题的解为多个不升数字序列。

  • 证明:存在最优解包含第一次的贪心选择,也就是说最大值ggg是某个数字序列的第一个数字。

    假设所有的最优解都中ggg都不是第一个数字,
    某最优解中,存在子序列a1,a2,...,g,...,ama_1, a_2, ...,g,..., a_ma1,a2,...,g,...,am,由于该子序列为不升子序列,那么a1≤a2≤...≤ga_1 \le a_2 \le ... \le ga1a2...g,而ggg是所有数字中的最大值,因而有g≥a1g \ge a_1ga1,所以a1=ga_1 = ga1=g,该序列的第一个数字就是ggg,与假设相悖,原命题得证。

  • 证明:假设前k次都进行贪心选择,存在最优解包含第k+1次的贪心选择ggg
    1) 如果ggg是某子序列的第一个数

    假设所有的最优解都不包含第一个数是ggg的子序列,任选一个最优解,存在在第k次选择后选择到的数字构成的子序列a1,a2,...,g,...,ama_1, a_2, ...,g,..., a_ma1,a2,...,g,...,am,由于该子序列为不升子序列,那么a1≥a2≥...≥ga_1 \ge a_2 \ge ... \ge ga1a2...g,而ggg是第k次选择后选择的数字中的最大值,因而有g≥a1g \ge a_1ga1,所以a1=ga_1 = ga1=g,该序列的第一个数字就是ggg,与假设相悖,原命题得证。

    2)如果ggg不是某子序列的第一个数
    也就是说,存在子序列ax,ax+1,...,aka_x, a_{x+1},... ,a_kax,ax+1,...,akaka_kak是第k次的贪心选择,前k次的贪心选择已经固定。下一次贪心选择是ggg,应该与aka_kak在同一序列且在aka_kak的后面。

    假设所有最优解中不存在aka_kak在子序列中的下一个数字是ggg的情况。
    1.如果aka_kakggg仍然在同一子序列,那么有:ax,...,ak,ak+1,...,g,...,ama_x,... ,a_k, a_{k+1}, ...,g, ..., a_max,...,ak,ak+1,...,g,...,am
    已知g是第k次贪心选择后选择的数字中的最大数字,那么有g≥ak+1g \ge a_{k+1}gak+1,因为这是不升序列,那么有ak+1≥ga_{k+1} \ge gak+1g,所以ak+1=ga_{k+1} = gak+1=gaka_kak的下一个数字是ggg,与假设相悖。
    2.如果aka_kakggg不在同一子序列中,
    ggg不可能接在由前k次贪心选择构成的老序列的后面。如果能接在老序列的后面,之前做贪心选择时就会选到ggg
    因而ggg所在的序列一定是由第k次贪心选择之后选择到的数字组成的,可能为:ay,ay+1,...,ag−1,g,ag+1,...,agea_y, a_{y+1}, ..., a_{g-1}, g, a_{g+1}, ..., a_{ge}ay,ay+1,...,ag1,g,ag+1,...,age。这是不升序列,所以ay≥ga_y \ge gayg
    由于ggg是第k次贪心选择后剩余数字中的最大数字,所以ay≤ga_y \le gayg,所以有ay=ga_y = gay=g
    因此g一定是某个序列中的第一个数字,该序列为:g,ag−1,g,ag+1,...,ageg, a_{g-1}, g, a_{g+1}, ..., a_{ge}g,ag1,g,ag+1,...,age
    第k次贪心选择aka_kak存在的序列为ax,ax+1,...,ak,ak+1,...,ama_x, a_{x+1},... ,a_k, a_{k+1}, ..., a_max,ax+1,...,ak,ak+1,...,am(也可能不存在ak+1,...,ama_{k+1}, ..., a_mak+1,...,am),
    由于g≤akg\le a_kgak,序列ax,ax+1,...,ak,g,ag+1,...,agea_x, a_{x+1},... ,a_k, g, a_{g+1}, ..., a_{ge}ax,ax+1,...,ak,g,ag+1,...,age一定也是不升序列。
    如果ak+1,...,ama_{k+1}, ..., a_mak+1,...,am不存在,则将ggg所在的序列接在aka_kak的后面,构成序列ax,ax+1,...,ak,g,ag+1,...,agea_x, a_{x+1},... ,a_k, g, a_{g+1}, ..., a_{ge}ax,ax+1,...,ak,g,ag+1,...,age,总序列数量减少,仍然是最优解。
    如果存在ak+1,...,ama_{k+1}, ..., a_mak+1,...,am,那么将序列g,ag+1,...,ageg, a_{g+1}, ..., a_{ge}g,ag+1,...,ageak+1,...,ama_{k+1}, ..., a_mak+1,...,am交换。得到序列ax,ax+1,...,ak,g,ag+1,...,agea_x, a_{x+1},... ,a_k, g, a_{g+1}, ..., a_{ge}ax,ax+1,...,ak,g,ag+1,...,ageak+1,...,ama_{k+1}, ..., a_mak+1,...,am,总序列数量不变,仍是最优解。
    无论何总情况,总能构造出满足aka_kak在子序列中下一个数字是ggg的最优解。与假设相悖,假设不成立,原命题得证。

  • 2. 具体做法

    将导弹高度记录在数组a中,设vis数组,表示第i个导弹是否已经被拦截。设h为无穷大。顺序遍历数组a,遇到小于等于h的数字,则拦截该导弹,记录拦截导弹的个数。
    遍历结束后,如果拦截到的导弹数量不足n,那么将h设为无穷大,再次遍历该数组。重复上述过程,直到拦截的数量等于n。输出遍历的次数。

    【题解代码】

    解法1:贪心

    #include<bits/stdc++.h> using namespace std; #define N 1005 #define INF 0x3f3f3f3f int main() {int a[N], n = 1, ct = 0, h, ans = 0;//ct:拦截的导弹数量 ans:遍历了几趟 bool vis[N] = {};while(cin >> a[n])n++;n--;while(ct < n){h = INF;for(int i = 1; i <= n; ++i){if(vis[i] == false && h >= a[i])//如果导弹i没被拦截 且 可以被拦截 {h = a[i];vis[i] = true;ct++;}}ans++;}cout << ans;return 0; }

    总结

    以上是生活随笔为你收集整理的信息学奥赛一本通 1322:【例6.4】拦截导弹问题(Noip1999)的全部内容,希望文章能够帮你解决所遇到的问题。

    如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。