首页 > 其他分享 >洛谷题单指南-动态规划2-P1020 [NOIP1999 提高组] 导弹拦截

洛谷题单指南-动态规划2-P1020 [NOIP1999 提高组] 导弹拦截

时间:2024-04-23 11:45:24浏览次数:19  
标签:数组 int 洛谷题 高度 导弹 P1020 NOIP1999 拦截 dp

原题链接:https://www.luogu.com.cn/problem/P1020

题意解读:拦截系统发射导弹的高度依次不增,计算能拦截的最大导弹数以及需要几套拦截系统。

解题思路:

问题1:最多能拦截多少导弹?

由于发射导弹高度不增,所以求一个最长不增子序列即可得到最大拦截数。

方法一、O(n^2)做法:动态规划。

采用LIS最长上升子序列类似的模版代码,判断条件不同而已。

设a[]是所有导弹高度,

设dp[i]表示以第i个数结尾的最长不增子序列,

if(a[j] >= a[i]) dp[i] = max(dp[i], dp[j] + 1)  ( j 取 1~i-1)

dp数组的最大值即最长不增子序列的长度。

方法二、O(nlogn)做法:单调栈+二分。

根据最长上升子序列单调栈优化的原理:

枚举每一个导弹,存入一个不增的数组(用数组模拟栈是便于二分);

如果导弹高度ai小于等于数组最后一个元素,则加入该数组尾部;

如果导弹高度ai大于数组最后一个元素,则通过二分查找到数组中<ai的第一个元素的位置,将该元素替换为ai;

最终,数组的长度即最长不增子序列的长度。

问题2:如果要拦截所有导弹最少要配备多少套这种导弹拦截系统?

采用贪心算法:

用数组保存所有拦截系统当前的高度,该数组确保递增排序;

如果当前已经有拦截系统,用二分查找到第一个大于等于当前导弹高度的位置,用导弹高度更新拦截系统高度;

如果找不到能拦截当前导弹的系统,则增加一个,其高度为当前导弹的高度,追加到拦截系统数组尾部;

最终,数组的长度即最少配备的拦截系统数量。

100分代码(动态规划):

#include <bits/stdc++.h>
using namespace std;

const int N = 100005;
int a[N], cnt; //所有导弹高度
int dp[N]; //dp[i]是以第i个数结尾的最长不增子序列长度 
int s[N], top; //拦截系统

int main()
{
    int x;
    while(cin >> x)
    {
        a[++cnt] = x;
    }

    //计算最长不增子序列
    for(int i = 1; i <= cnt; i++)
    {
        dp[i] = 1;
        for(int j = 1; j < i; j++)
        {
            if(a[j] >= a[i]) dp[i] = max(dp[i], dp[j] + 1);
        }
    }
    int maxx = 0;
    for(int i = 1; i <= cnt; i++) maxx = max(maxx, dp[i]);
    cout << maxx << endl;

    //计算导弹系统数
    for(int i = 1; i <= cnt; i++)
    {
        if(top == 0 || a[i] > s[top]) s[++top] = a[i]; //如果没有拦截系统或者已有拦截系统都无法拦截,就发射一个,高度等于当前导弹高度
        else //否则二分找到第一个>=a[i]的位置,进行替换,表示拦截到导弹后,高度减少,这里即体现贪心思想,用一个刚好能拦截的系统进行拦截
        {
            int l = 1, r = top, ans = -1;
            while(l <= r)
            {
                int mid = (l + r) >> 1;
                if(s[mid] >= a[i])
                {
                    ans = mid;
                    r = mid - 1;
                }
                else l = mid + 1;
            }
            s[ans] = a[i];
        }
    }
    cout << top << endl;

    return 0;
}

100分代码(单调栈+二分):

#include <bits/stdc++.h>
using namespace std;

const int N = 100005;
int a[N], cnt; //所有导弹高度
int l[N], topl; //l保存最长不增子序列,是一个单调不增的数组
int s[N], tops; //拦截系统

int main()
{
    int x;
    while(cin >> x)
    {
        a[++cnt] = x;
    }

    //计算最长不增子序列
    for(int i = 1; i <= cnt; i++)
    {
        if(topl == 0 || l[topl] >= a[i]) l[++topl] = a[i]; //如果数组空或者栈顶比a[i]小,把a[i]入栈
        else
        {
            int left = 1, right = topl, ans = -1;
            while(left <= right)
            {
                int mid = (left + right) >> 1;
                if(l[mid] < a[i]) //找到<a[i]的第一个
                {
                    ans = mid;
                    right = mid - 1;
                }
                else left = mid + 1;
            }
            l[ans] = a[i]; 
        }
    }
    cout << topl << endl;

    //计算导弹系统数
    for(int i = 1; i <= cnt; i++)
    {
        if(tops == 0 || a[i] > s[tops]) s[++tops] = a[i]; //如果没有拦截系统或者已有拦截系统都无法拦截,就发射一个,高度等于当前导弹高度
        else //否则二分找到第一个>=a[i]的位置,进行替换,表示拦截到导弹后,高度减少,这里即体现贪心思想,用一个刚好能拦截的系统进行拦截
        {
            int left = 1, right = tops, ans = -1;
            while(left <= right)
            {
                int mid = (left + right) >> 1;
                if(s[mid] >= a[i])
                {
                    ans = mid;
                    right = mid - 1;
                }
                else left = mid + 1;
            }
            s[ans] = a[i];
        }
    }
    cout << tops << endl;

    return 0;
}

 

标签:数组,int,洛谷题,高度,导弹,P1020,NOIP1999,拦截,dp
From: https://www.cnblogs.com/jcwy/p/18152513

相关文章

  • 洛谷题单指南-动态规划1-P1064 [NOIP2006 提高组] 金明的预算方案
    原题链接:https://www.luogu.com.cn/problem/P1064题意解读:用固定钱数购买最大价值的物品。解题思路:背包问题,背包问题里的体积相当于物品价格,价值相当于价格*重要度物品分为主件、附件,主件最多有0/1/2个附件,要选附件必须选相应主件,因此在递推计算dp[j]总价格j能购买的最大价......
  • 洛谷题单指南-动态规划1-P3842 [TJOI2007] 线段
    原题链接:https://www.luogu.com.cn/problem/P3842题意解读:计算1-n的最短路,且每行要覆盖线段。解题思路:既然要每行覆盖线段,那往下一行走时,必然是从线段的端点往下,有可能是从左端点往下,也有可能是从右端点往下。当已知第i行,从1走到第i行的左端点且要覆盖第i行线段的路程可以计算......
  • 洛谷题单指南-动态规划1-P1077 [NOIP2012 普及组] 摆花
    原题链接:https://www.luogu.com.cn/problem/P1077题意解读:n种花选m个的选法,每种花数量为ai。解题思路:设dp[i][j]表示前i种花选j个的选法对于第i种花,可以选0,1,2...min(ai,j)个则有递推式:dp[i][j]=∑dp[i-1][j-k],k取0,1,2...min(ai,j)初始化dp[0][0]=1100分代码:#incl......
  • 洛谷题单指南-动态规划1-P1049 [NOIP2001 普及组] 装箱问题
    原题链接:https://www.luogu.com.cn/problem/P1049题意解读:装尽可能多的物品,使得总体积越大越好,即剩余空间最小,还是一个01背包问题,物品的体积就是其价值。解题思路:01背包模版题,物品体积、价值相同,直接采用一维dp。100分代码:#include<bits/stdc++.h>usingnamespacestd;co......
  • 洛谷题单指南-动态规划1-P1115 最大子段和
    原题链接:https://www.luogu.com.cn/problem/P1115题意解读:计算最大字段和,典型dp问题。解题思路:设a[]表示所有整数,f[i]表示以第i个数结束的最大字段和当f[i-1]>=0时,f[i]=f[i-1]+a[i]否则,f[i]=a[i]因此,递归式为f[i]=max(a[i],f[i-1]+a[i])注意整数可能为负,ans初始......
  • 洛谷题单指南-动态规划1-P1434 [SHOI2002] 滑雪
    原题链接:https://www.luogu.com.cn/problem/P1434题意解读:计算能滑行的最长距离。解题思路:设dp(i,j)表示从i,j可以滑行的最大距离对于4个方向i,j可以到达的点,ni,nj,如果可以滑过去(ni,ni所在点高度更低)则dp(i,j)=max(dp(i,j),1+dp(ni,nj))为了便于搜索4个方向的各条路径,......
  • 洛谷题单指南-动态规划1-P2196 [NOIP1996 提高组] 挖地雷
    原题链接:https://www.luogu.com.cn/problem/P2196题意解读:求一条路径,使得所有点地雷数之和最大。解题思路:1、DFS先建图,再从1~n点分别进行一次DFS,记录过程中地雷总数最大的,并且同时记录遍历的顺序。数据量不大,直接就可以过。100分代码:#include<bits/stdc++.h>usingnamespa......
  • 洛谷题单指南-动态规划1-P1216 [USACO1.5] [IOI1994]数字三角形 Number Triangles
    原题链接:https://www.luogu.com.cn/problem/P1216题意解读:计算数字三角形最高点到最后一行路径之和最大值,典型线性DP。解题思路:设a[i][j]表示数字三角形的值,设dp[i][j]表示从最高点到第i行第j列路径之和的最大值,由于每一步可以走到左下方的点也可以到达右下方的点,所以dp[i][......
  • 洛谷题单指南-数学基础问题-P1403 [AHOI2005] 约数研究
    原题链接:https://www.luogu.com.cn/problem/P1403题意解读:计算1~n每个数的约数个数之和。解题思路:1、数学方法1~n的约数范围也在1~n,要计算每个数的约数个数之和可以从约数出发,比如约数是x,那么在1~n中一共有n/x个数包含x这个约数x从1一直枚举到n,就可以得出每个约数是多少个......
  • 洛谷题单指南-数学基础问题-P3601 签到题
    原题链接:https://www.luogu.com.cn/problem/P3601题意解读:求l~r范围内所有qiandao(x)之和,qiandao(x)为小于等于x的数中,与x不互质的数的个数。注意取模。解题思路:欧拉函数定义:phi(x)=x*(1-1/p1)*(1-1/p2)*...*(1-1/pn),p1,p2...pn为x的所有质因子其中:phi(x)表示1~x中所......