当前位置: 首页 > article >正文

acwing算法提高之动态规划--最长上升子序列模型(下)

目录

  • 1 基础知识
  • 2 模板
  • 3 工程化

1 基础知识

暂无。。。

2 模板

暂无。。。

3 工程化

题目1:拦截导弹。给你N个数,第(1)问求最长下降子序列,第(2)问求需要多少个下降序列才能把所有元素覆盖住?

解题思路:第(1)直接用最长上升子序列的模型即可。第(2)问,需要贪心做法。

贪心做法的关键步骤,有

  1. 遍历每一个元素x:
  2. 如果现有子序列结尾值均小于等于x,新开一个下降子序列,x作为第一个元素。否则,将x插入到最不浪费空间的那个子序列结尾处(即大于等于x的最小值)。
  3. 开了多少个下降子序列,就是最终答案。

通过发现可以得到,上述贪心做法,和最长上升子序列的 O ( n l o g n ) O(nlogn) O(nlogn)做法一致,虽然代表的含义是不一样的,但答案是一样的。

C++代码如下,

#include <iostream>
#include <vector>

using namespace std;

const int N = 1010;
int n;
int a[N];
int f[N];

int main() {
    while (cin >> a[n]) n++;
    
    int ans1 = 0;
    for (int i = 0; i < n; ++i) {
        f[i] = 1;
        for (int j = 0; j < i; ++j) {
            if (a[j] >= a[i]) {//注意可以取等于号
                f[i] = max(f[i], f[j] + 1);
            }
        }
        ans1 = max(ans1, f[i]);
    }
    cout << ans1 << endl;
    
    //求需要多少个下降子序列才能够把所有元素覆盖住
    vector<int> vec;
    for (int i = 0; i < n; ++i) {
        //在vec中找到大于a[i],且值最小的元素的下标
        int idx = -1;
        for (int j = 0; j < vec.size(); ++j) {
            if (vec[j] >= a[i]) {//注意可以取等于号
                idx = j;
                break;
            }
        }
        if (idx == -1) {//说明没有找到,vec中的元素都比a[i]要小
            vec.emplace_back(a[i]);
        } else {//说明找到了
            vec[idx] = a[i];
        }
    }
    cout << vec.size() << endl;
    
    return 0;
}

可以将第(2)问求需要多少个下降子序列才能够把元素覆盖住,转换为求最长上升子序列。C++代码如下,

#include <iostream>
#include <vector>
#include <cstring>

using namespace std;

const int N = 1010;
int n;
int a[N];
int f[N];

int main() {
    while (cin >> a[n]) n++;
    
    int ans1 = 0;
    for (int i = 0; i < n; ++i) {
        f[i] = 1;
        for (int j = 0; j < i; ++j) {
            if (a[j] >= a[i]) {//注意可以取等于号
                f[i] = max(f[i], f[j] + 1);
            }
        }
        ans1 = max(ans1, f[i]);
    }
    cout << ans1 << endl;
    
    //求需要多少个下降子序列才能够把所有元素覆盖住
    memset(f, 0, sizeof f);
    //转换成求最长上升子序列
    int ans2 = 0;
    for (int i = 0; i < n; ++i) {
        f[i] = 1;
        for (int j = 0; j < i; ++j) {
            if (a[j] < a[i]) {
                f[i] = max(f[i], f[j] + 1);
            }
        }
        ans2 = max(ans2, f[i]);
    }
    cout << ans2 << endl;
    
    return 0;
}

更进一步,可以将上述求最长上升子序列的做法的时间复杂度从 O ( n 2 ) O(n^2) O(n2)优化到 O ( n l o g n ) O(nlogn) O(nlogn)。C++代码如下,

#include <iostream>
#include <vector>
#include <cstring>

using namespace std;

const int N = 1010;
int n;
int a[N];
int f[N];

int main() {
    while (cin >> a[n]) n++;
    
    int ans1 = 0;
    for (int i = 0; i < n; ++i) {
        f[i] = 1;
        for (int j = 0; j < i; ++j) {
            if (a[j] >= a[i]) {//注意可以取等于号
                f[i] = max(f[i], f[j] + 1);
            }
        }
        ans1 = max(ans1, f[i]);
    }
    cout << ans1 << endl;
    
    //求需要多少个下降子序列才能够把所有元素覆盖住
    vector<int> q; //q[i]表示长度为length(length = i + 1)的上升子序列的结尾元素的最小值为q[i]
    for (int i = 0; i < n; ++i) {
        //在q中找到大于等于a[i]的第一个元素
        int idx = lower_bound(q.begin(), q.end(), a[i]) - q.begin();
        if (idx == q.size()) {//说明没有找到,q中所有的元素都小于a[i]
            q.emplace_back(a[i]);
        } else {//说明找到了
            q[idx] = a[i]; 
        }
    }
    int ans2 = q.size();
    cout << ans2 << endl;
    
    return 0;
}

题目2:导弹防御系统。

解题思路:dfs。

C++代码如下,

#include <iostream>

using namespace std;

const int N = 55;
int a[N];
int up[N];
int down[N];
int n;
int ans;

void dfs(int u, int sup, int sdown) {
    if (sup + sdown >= ans) return;
    if (u == n) {
        ans = sup + sdown;
        return;
    }
    
    //(1)将a[u]归到上升子序列中
    int k = 0;
    while (k < sup && up[k] >= a[u]) k++;
    if (k < sup) {
        int t = up[k];
        up[k] = a[u];
        dfs(u + 1, sup, sdown);
        up[k] = t;
    } else {
        up[k] = a[u];
        dfs(u + 1, sup + 1, sdown);
    }
    
    //(2)将a[u]归到下降子序列中
    k = 0;
    while (k < sdown && down[k] <= a[u]) k++;
    if (k < sdown) {
        int t = down[k];
        down[k] = a[u];
        dfs(u + 1, sup, sdown);
        down[k] = t;
    } else {
        down[k] = a[u];
        dfs(u + 1, sup, sdown + 1);
    }
    return;
}

int main() {
    while (cin >> n, n) {
        for (int i = 0; i < n; ++i) cin >> a[i];
        
        ans = n;
        dfs(0, 0, 0);
        cout << ans << endl;
    }
    
    return 0;
}

题目3


http://www.kler.cn/a/158908.html

相关文章:

  • Go语言24小时极速学习教程(二)复合数据(集合)操作
  • OMV7 树莓派 tf卡安装
  • MySQL技巧之跨服务器数据查询:基础篇-A数据库与B数据库查询合并--封装到存储过程中
  • Java基础-I/O流
  • RTSP播放器EasyPlayer.js播放器UniApp或者内嵌其他App里面webview需要截图下载
  • uniapp微信小程序接入airkiss插件进行WIFI配网
  • java项目日常运维需要的文档资料
  • mysql常见配置文件参数
  • 轨道交通数字孪生可视化平台,助力城市交通运营智慧化
  • 超完整的mysql安装配置方法(包含idea和navicat连接mysql,并实现建表)
  • 列表插槽使用
  • 我的计算机之旅:为何选择这个领域?
  • 电力校准平台
  • 高性能网络编程 - 白话TCP 三次握手过程
  • 8.HTTP工作原理
  • 你知道小红书小眼睛的推送机制吗?
  • 6页手写笔记总结信号与系统常考知识大题知识点
  • Servlet作业1
  • C语言-字符串
  • 如何使用C++开发集群服务
  • html实现各种好看的鼠标滑过图片特效模板
  • Java+Swing+Mysql实现超市管理系统
  • CSS中常用的5种颜色单位
  • HTTP会话技术---Cookie、Session和Token介绍及它们在JavaWeb中的使用
  • 手机充电 显示连接耳机 (充电没外放声音) 并且充电速度很慢
  • 【python】包(package)与模块(module)、import、__name__与__main__