dp----最长上升子序列问题

最原始问题:

 1 给定一个长度为 N 的数列,求数值严格单调递增的子序列的长度最长是多少。
 2 
 3 输入格式
 4 第一行包含整数 N。
 5 
 6 第二行包含 N 个整数,表示完整序列。
 7 
 8 输出格式
 9 输出一个整数,表示最大长度。
10 
11 数据范围
12 1≤N≤100013109≤数列中的数≤109
14 输入样例:
15 7
16 3 1 2 1 8 5 6
17 输出样例:
18 4

最原始解法:

 《变式----最长上升子序列+最长下降子序列》

1014. 登山

五一到了,ACM队组织大家去登山观光,队员们发现山上一共有N个景点,并且决定按照顺序来浏览这些景点,即每次所浏览景点的编号都要大于前一个浏览景点的编号。

同时队员们还有另一个登山习惯,就是不连续浏览海拔相同的两个景点,并且一旦开始下山,就不再向上走了。

队员们希望在满足上面条件的同时,尽可能多的浏览景点,你能帮他们找出最多可能浏览的景点数么?

输入格式
第一行包含整数N,表示景点数量。

第二行包含N个整数,表示每个景点的海拔。

输出格式
输出一个整数,表示最多能浏览的景点数。

数据范围
2≤N≤1000
输入样例:
8
186 186 150 200 160 130 197 220
输出样例:
4
题源:AcWing 1014. 登山

 

 代码:

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <cstring>
 4 using namespace std;
 5 const int N = 1010;
 6 int ldp[N], rdp[N], h[N];
 7 int main()
 8 {
 9     int n;
10     scanf("%d", &n);
11     for (int i = 1; i <= n; i++)
12     {
13         scanf("%d", &h[i]);
14     }
15     for (int i = 1; i <= n; i++)
16     {
17         ldp[i] = 1;//注意千万不能忘记这一步,因为就算什么都比不上,还有自己这个
18         for (int j = 1; j < i; j++)
19         {
20             if (h[j] < h[i])
21             {
22                 ldp[i] = max(ldp[i], ldp[j] + 1);
23             }
24         }
25     }
26     for (int i=n;i>=1;i--)
27     {
28         for (int j=n;j>=i+1;j--)
29         {
30             if (h[i]>h[j])
31             {
32                 rdp[i]=max(rdp[i],rdp[j]+1);
33             }
34         }
35         ldp[i]+=rdp[i];
36     }
37     int ans = 0;
38     for (int i = 1; i <= n; i++)
39     {
40         ans = max(ldp[i], ans);
41     }
42     printf("%d", ans);
43     return 0;
44 }

 《最长上升子序列问题----其中的贪心问题》

1010. 拦截导弹
拦截导弹袭击,发展出一种导弹拦截系统。

但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。

某天,雷达捕捉到敌国的导弹来袭。

由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。

输入导弹依次飞来的高度(雷达给出的高度数据是不大于30000的正整数,导弹数不超过1000),计算这套系统最多能拦截多少导弹,如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。

输入格式
共一行,输入导弹依次飞来的高度。

输出格式
第一行包含一个整数,表示最多能拦截的导弹数。

第二行包含一个整数,表示要拦截所有导弹最少要配备的系统数。

数据范围
雷达给出的高度数据是不大于 30000 的正整数,导弹数不超过 1000。

输入样例:
389 207 155 300 299 170 158 65
输出样例:
6
2

主要是第二问:

要拦截所有导弹最少要配备的系统数。

 关于为什么g是一个单调递增的数组,是因为g每次新开一个都是因为现在的导弹高度都大于已有的系统记录高度

#include <iostream>
#include <algorithm>
#include <cstring>
#include <sstream>
using namespace std;
const int N = 1010;
int h[N], dp[N];
int main()
{
    string str;
    getline(cin, str);
    stringstream ssin(str);
    int cnt = 1;
    while (ssin >> h[cnt])
        cnt++;
    cnt--;
    /*  for (int i=1;i<=cnt;i++)
     {
         cout<<h[i]<<" ";
     }
     cout<<endl; */
    int maxNum = 0;
    for (int i = cnt; i >= 1; i--)
    {
        dp[i] = 1;
        for (int j = cnt; j >= i + 1; j--)
        {
            if (h[i] >= h[j])
            {
                dp[i] = max(dp[i], dp[j] + 1);
            }
        }
        maxNum = max(maxNum, dp[i]);
    }
    cout << maxNum << endl;
    int g[N], cot = 0;
    //g[N]保存的是每一套系统最后拦截的导弹的高度
    //cot是现在系统拥有的个数
    for (int i = 1; i <= cnt; i++)//对于每一个导弹都要拦截,所以枚举每一个导弹
    {
        int k = 1;//每次从第一个系统开始看
        while (k <= cot && h[i] > g[k]) //按我这个思想,能够保证g是一个递增的数组
            k++;//当h[i]<=g[k]时,就是找到了最小的且大于等于h[i]的系统计入数
        g[k] = h[i];//找到了更新一下,没找到则开一个新的系统
        if (k > cot)
            cot++;//系统数更新
    }
    cout<<cot;
    return 0;
}

 

posted @ 2022-06-24 17:20  次林梦叶  阅读(28)  评论(0)    收藏  举报