動的計画法-(落下することなく最長のサブシーケンス)

参照:https//oi-wiki.org/dp/basic/

O(n ^ 2)アルゴリズム

毎回最初からスキャンして、最良の答えを見つけてください。

int a[MAXN], d[MAXN];
int dp() {
    
    
  d[1] = 1;
  int ans = 1;
  for (int i = 2; i <= n; i++) {
    
    
    for (int j = 1; j < i; j++)
      if (a[j] <= a[i]) {
    
    
        d[i] = max(d[i], d[j] + 1);
        ans = max(ans, d[i]);
      }
  }
  return ans;
}

O(nlogn)アルゴリズムの二分法

この記事https://www.cnblogs.com/itlqs/p/5743114.htmlを参照すると
ここに画像の説明を挿入
、コードは次のようになります。

for (int i = 0; i < n; ++i) scanf("%d", a + i);
memset(dp, 0x1f, sizeof dp);
mx = dp[0];
for (int i = 0; i < n; ++i) {
    
    
  *std::upper_bound(dp, dp + n, a[i]) = a[i];
}
ans = 0;
while (dp[ans] != mx) ++ans;

質問の例:https//vijos.org/p/1303

説明

ある国は、敵のミサイル攻撃から身を守るためにミサイル迎撃システムを開発しました。ただし、このミサイル迎撃システムには欠点があります。最初のシェルは任意の高さに達することができますが、後続の各シェルを前のシェルより高くすることはできません。ある日、レーダーが敵のミサイル攻撃を捕らえました。システムはまだ実験段階であるため、システムは1つしかないため、すべてのミサイルを迎撃できない可能性があります。

フォーマット

入力フォーマット

入力データは1行のみで、この行には、ミサイルの高さを順番に示す、半値幅のコンマで区切られた複数のデータが含まれます(ミサイルは最大20個あり、高さは30,000以下の正の整数です)。 )。

出力フォーマット

出力データは1行のみで、この行にはコンマで区切られた2つのデータが含まれています。最初のデータは、このシステムが迎撃できるミサイルの最大数を示しています。2番目のデータは、すべてのミサイルを迎撃するために、このようなシステムをさらにいくつ追加する必要があるかを示しています。

例1

サンプル入力1

389,207,155,300,299,170,158,65

サンプル出力1

6,1

制限

各テストポイントには1秒の制限時間があります。

問題解決

コード

#include <algorithm>
#include <iostream>
#include <stack>
#include <string>
#include <vector>
using namespace std;
const int maxn = 1e5 + 2;
int dp[maxn];  // dp[k]表示长度为k的不下降子序列末尾元素的最小值
// int minh[maxn];  //记录从第i项开始,剩下最大能消灭的导弹数量
vector<int> v;

int up_bound(int l, int r, int x) {
    
      //找到第一个大于x的数的下标
    while (l < r) {
    
    
        int mid = (r + l) / 2;
        if (x >= dp[mid])
            l = mid + 1;
        else
            r = mid;
    }
    return l;
}
int down_bound(int l, int r, int x) {
    
      //找到第一个小于等于x的数的下标
    for (int i = l; i <= r; i++)
        if (dp[i] <= x) return i;
    return r;
}

int main() {
    
    
    char ch;
    int n;
    while (true) {
    
    
        scanf("%d", &n);
        v.push_back(n);
        ch = getchar();
        if (ch == '\n') break;
    }

    v.push_back(0);
    reverse(v.begin(), v.end());

    int len = 1;
    dp[1] = v[1];
    for (int i = 2; i < v.size(); i++) {
    
      //求出最长不降子序列
        if (v[i] >= dp[len]) {
    
    
            dp[++len] = v[i];
        } else {
    
    
            int up = up_bound(1, len, v[i]);
            dp[up] = v[i];
        }
    }

    cout << len << ",";
    //第二问就出最大下降子序列
    len = 1;
    dp[1] = v[1];
    for (int i = 2; i < v.size(); i++) {
    
    
        if (v[i] < dp[len])
            dp[++len] = v[i];
        else {
    
    
            int down = down_bound(1, len, v[i]);
            dp[down] = v[i];
        }
    }

    cout << len - 1 << endl;

    return 0;
}
/*90 103 99 83 102 70 86 70 99 71*/

おすすめ

転載: blog.csdn.net/qq_45349225/article/details/109405029