饥饿的牛(最长递增子序列)
链接:https://ac.nowcoder.com/acm/problem/25148
来源:牛客网
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
题目:
题目描述
现在,你得到了这一次开饭前队伍中从前到后所有奶牛的编号。奶牛们想请你计算一下,按照FJ的规定,最多有多少头奶牛能吃上饭?
比如说,有11头奶牛按以下顺序排好了队(数字代表奶牛的编号)
2 5 18 3 4 7 10 9 11 8 15
对于这个队列,最多可以让7头奶牛吃上饭,她们的编号分别为2,3,4,7,10,11,15。队列2,5,3,10,15是不合法的,因为第3头奶牛的编号(3)小于她前面一头奶牛的编号(5)。
输入描述:
第1行: 一个整数,N
第2..?行: 除了最后一行,每一行都包含恰好20个用空格隔开的整数,依次表 示队伍中从前到后的奶牛的编号。如果N不能整除20,那么最后一行包含的数字不到20个
输出描述:
第1行: 输出按照FJ的规定,最多可以挑出的奶牛的数目
输入
11 2 5 18 3 4 7 10 9 11 8 15
输出
7
方法一:O(logn),很难懂
i | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
arr[i] | 1 | 7 | 3 | 4 | 9 | 4 |
8 |
j | 0 | ...... |
number[j] | -INT_MAX |
开始判断:
刚开始时候,p指向number数组的j位置(p=0),arr[0]=1>number[1] => p++,number[p]=arr[0]
j | 0 | 1 | ...... |
number[j] | -INT_MAX | 1(arr[0]) |
此时p=1,arr[1]=7>number[p] => p++,number[p]=arr[1]
j | 0 | 1 | 2 | ...... |
number[j] | -INT_MAX | 1(arr[0]) | 7(arr[1) |
此时p=2,arr[2]=3<number[p] => 搜索如果将3插入到number数组中,应该在的位置,用lower_bounder函数,发现position=2,则number[position]=arr[2]=3
j | 0 | 1 | 2 | ...... |
number[j] | -INT_MAX | 1(arr[0]) | 7(arr[1)->3(arr[2]) | |
此时p=2,arr[3]=4>number[p] => p++,number[p]=arr[3]
j | 0 | 1 | 2 | 3 | ...... |
number[j] | -INT_MAX | 1(arr[0]) | 3(arr[2]) | 4(arr[3]) | |
此时p=3,arr[4]=9>number[p] => p++,number[p]=arr[4]
j | 0 | 1 | 2 | 3 | 4 | ...... |
number[j] | -INT_MAX | 1(arr[0]) | 3(arr[2]) | 4(arr[3]) | 9(arr[4]) | |
此时p=4,arr[5]=4<number[p] => position=lower_bounder(number,number+p,arr[i])=3,number[position]=arr[5]=4
j | 0 | 1 | 2 | 3 | 4 | ...... |
number[j] | -INT_MAX | 1(arr[0]) | 3(arr[2]) | 4(arr[3])->4(arr[5]) | 9(arr[4]) | |
此时p=4,arr[6]=8<number[p] => position=lower_bounder(number,number+p,arr[i])=4,number[position]=arr[6]=8
j | 0 | 1 | 2 | 3 | 4 | ...... |
number[j] | -INT_MAX | 1(arr[0]) | 3(arr[2]) | 4(arr[3]/arr[5]) | 9(arr[4])->8(arr[6]) | |
number数组的结果:
j | 0 | 1 | 2 | 3 | 4 |
number[j] | -INT_MAX | 1(arr[0]) | 3(arr[2]) | 4(arr[3]/arr[5]) | 8(arr[6]) |
number下标最高位4表示最长的就是长度为4的子序列
/* ------------------------------------------------- Author: wry date: 2022/3/1 17:10 Description: test ------------------------------------------------- */ #include <bits/stdc++.h> using namespace std; const int MAXN =5000+10; int arr[MAXN]; int number[MAXN]; //表示以number[i]结尾的最长子序列有i个 int main() { int n; cin >> n; for (int i=0;i<n;i++) { cin >> arr[i]; } number[0] = -INT_MAX; //0号位置作为哨兵 int p = 0; //定位需要处理的number位置 for (int i=0;i<n;i++) { if (arr[i]>number[p]) { p++; number[p] = arr[i]; } else if(arr[i]<=number[p]) { int position = lower_bound(number,number+p,arr[i]) - number; //返回arr[i]可以在number数组中插入的位置 number[position] = arr[i]; //将值变成最小的 } } cout << p << endl; return 0; }
方法二:递归+记忆化 O(n^2)
Note:用maxlength数组记录下标为j结尾的最长子序列长度,初始化为-1表示还没有处理过,但是当处理它时,将它初始化为1,表示最少就有长度为1的最长子序列,每次对比它之前的所有值,如果比它小就判断它自身已知的最长子序列和以比它小的那个子序列长度+1,取其中更大的值
/* ------------------------------------------------- Author: wry date: 2022/3/1 17:10 Description: test ------------------------------------------------- */ #include <iostream> using namespace std; const int MAXN =5000+10; int arr[MAXN]; int maxlength[MAXN]; //记录每个元素的最长子序列长度 int Fun(int j) { //表示以下标为j元素结尾,最长子序列 if (maxlength[j]!=-1) { return maxlength[j]; } if (j==0) { maxlength[j] = 1; } else { maxlength[j] = 1; //因为每个值至少都是1开始 for (int i=0;i<j;i++) { if (arr[i]<arr[j]) { maxlength[j] = max(maxlength[j],Fun(i)+1); } } } return maxlength[j]; } int main() { int n; cin >> n; fill(maxlength,maxlength+n,-1); //初始化 for (int i=0;i<n;i++){ cin >> arr[i]; } int maxlong = -1; for (int i=0;i<n;i++) { maxlong = max(maxlong,Fun(i)); } cout << maxlong << endl; return 0; }
(这是我第二次写的,能通过本题,也能通过北大POJ最长递增子序列)
/* ------------------------------------------------- Author: wry date: 2022/3/4 0:45 Description: test ------------------------------------------------- */ #include <iostream> #include <algorithm> #include <cmath> using namespace std; const int MAXN = 5000+10; int arr[MAXN]; int length[MAXN]; //以i结尾的最长递增子序列 void Fun(int n) { for (int i=0;i<n;i++) { length[i] = 1; if (i!=0) { for (int j = 0; j < i; j++) { if (arr[j] < arr[i] && length[j] + 1 > length[i]) { length[i] = length[j] + 1; } } } } } int main() { int n; cin >> n; for (int i=0;i<n;i++) { cin >> arr[i]; } Fun(n); int maxl = length[0]; for (int i=1;i<n;i++) { maxl = max(maxl,length[i]); } cout << maxl << endl; return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现