目录
一个数的序列bibi,当b1
你的任务,就是对于给定的序列,求出最长上升子序列的长度。
输入的第一行是序列的长度N(1≤N≤1000)。第二行给出序列中的N个整数,这些整数的取值范围都在0到10000。
最长上升子序列的长度。
7
1 7 3 5 9 4 8
4
- #include
- using namespace std;
- const int N=1010;
- int f[N],a[N],g[N];
- int main()
- {
- int n;
- cin>>n;
- for(int i=0;i
- cin>>a[i];
- for(int i=0;i
- {
- f[i]=1;
- for(int j=0;j
- {
- f[i]=max(f[i],f[j]+1);
- // if(f[i]
- // {
- // f[i]=f[j]+1;
- // g[i]=j;
-
- // }
- }
- }
-
- // int k = 1;
- // for (int i = 1; i <= n; i ++)
- // if (f[i] > f[k]) k = i;
- // cout << f[k] << endl;
-
- // for (int i = 0, len = f[k]; i < len; i ++)
- // {
- // cout << a[k] << ' ';
- // k = g[k];
- // }
- int res=0;
- for(int i=0;i
- res=max(res,f[i]);
- cout<
- return 0;
- }
-
-
怪盗基德的滑翔翼
【题目描述】
怪盗基德是一个充满传奇色彩的怪盗,专门以珠宝为目标的超级盗窃犯。而他最为突出的地方,就是他每次都能逃脱中村警部的重重围堵,而这也很大程度上是多亏了他随身携带的便于操作的滑翔翼。
有一天,怪盗基德像往常一样偷走了一颗珍贵的钻石,不料却被柯南小朋友识破了伪装,而他的滑翔翼的动力装置也被柯南踢出的足球破坏了。不得已,怪盗基德只能操作受损的滑翔翼逃脱。
假设城市中一共有N幢建筑排成一条线,每幢建筑的高度各不相同。初始时,怪盗基德可以在任何一幢建筑的顶端。他可以选择一个方向逃跑,但是不能中途改变方向(因为中森警部会在后面追击)。因为滑翔翼动力装置受损,他只能往下滑行(即:只能从较高的建筑滑翔到较低的建筑)。他希望尽可能多地经过不同建筑的顶部,这样可以减缓下降时的冲击力,减少受伤的可能性。请问,他最多可以经过多少幢不同建筑的顶部(包含初始时的建筑)?
【输入】
输入数据第一行是一个整数K(K<100) ,代表有KK组测试数据。
每组测试数据包含两行:第一行是一个整数N(N<100)N(N<100),代表有N幢建筑。第二行包含NN个不同的整数,每一个对应一幢建筑的高度h(0
【输出】
对于每一组测试数据,输出一行,包含一个整数,代表怪盗基德最多可以经过的建筑数量。
【输入样例】
3
8
300 207 155 299 298 170 158 65
8
65 158 170 298 299 155 207 300
10
2 1 3 4 5 6 7 8 9 10
【输出样例】
6
6
9
-
- #include
- using namespace std;
- const int N=1010,INF=0x3f3f3f3f;
- int a[N],f[N],g[N];
- int main()
- {
- int t;
- cin>>t;
- while(t--)
- {
- int n;
- cin>>n;
- memset(f,0,sizeof f);
- memset(g,0,sizeof g);
- for(int i=1;i<=n;i++)
- cin>>a[i];
- for(int i=1;i<=n;i++)
- {
- f[i]=1;
- for(int j=1;j<=i;j++)
- f[i]=max(f[i],f[j]+1);
- }
- for(int i=n;i>=1;i--)
- {
- g[i]=1;
- for(int j=n;j>=i;j--)
- g[i]=max(g[i],g[j]+1);
- }
- for(int i=1;i<=n;i++)
- f[i]=max(f[i],g[i]);
- int res=-INF;
- for(int i=1;i<=n;i++)
- res=max(res,f[i]);
- cout<
- }
-
- }
登山
【题目描述】
五一到了,ACM队组织大家去登山观光,队员们发现山上一共有N个景点,并且决定按照顺序来浏览这些景点,即每次所浏览景点的编号都要大于前一个浏览景点的编号。同时队员们还有另一个登山习惯,就是不连续浏览海拔相同的两个景点,并且一旦开始下山,就不再向上走了。队员们希望在满足上面条件的同时,尽可能多的浏览景点,你能帮他们找出最多可能浏览的景点数么?
【输入】
第一行:N (2 <= N <= 1000) 景点数;
第二行:N个整数,每个景点的海拔。
【输出】
最多能浏览的景点数。
【输入样例】
8
186 186 150 200 160 130 197 220
【输出样例】
4
-
- #include
- using namespace std;
- const int N=1010,INF=0x3f3f3f3f;
- int a[N],f[N],g[N];
- int main()
- {
-
- int n;
- cin>>n;
-
- for(int i=1;i<=n;i++)
- cin>>a[i];
- for(int i=1;i<=n;i++)
- {
- f[i]=1;
- for(int j=1;j<=i;j++)
- f[i]=max(f[i],f[j]+1);
- }
- for(int i=n;i>=1;i--)
- {
- g[i]=1;
- for(int j=n;j>=i;j--)
- g[i]=max(g[i],g[j]+1);
- }
-
- int res=-INF;
- for(int i=1;i<=n;i++)
- res=max(res,f[i]+g[i]-1);
- cout<
-
- }
合唱队形
【题目描述】
NN位同学站成一排,音乐老师要请其中的(N−K)位同学出列,使得剩下的KK位同学排成合唱队形。
合唱队形是指这样的一种队形:设KK位同学从左到右依次编号为1,2,…,K,他们的身高分别为T1,T2,…,TK,则他们的身高满足T1Ti+1>…>TK(1≤i≤K)。
你的任务是,已知所有NN位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形。
【输入】
输入的第一行是一个整数N(2≤N≤100)N,表示同学的总数。第二行有nn个整数,用空格分隔,第ii个整数Ti(130≤Ti≤230)是第i位同学的身高(厘米)。
【输出】
输出包括一行,这一行只包含一个整数,就是最少需要几位同学出列。
【输入样例】
8
186 186 150 200 160 130 197 220
【输出样例】
4
和登山一样,需要改一下结果,要取出人
-
- #include
- using namespace std;
- const int N=1010,INF=0x3f3f3f3f;
- int a[N],f[N],g[N];
- int main()
- {
-
- int n;
- cin>>n;
-
- for(int i=1;i<=n;i++)
- cin>>a[i];
- for(int i=1;i<=n;i++)
- {
- f[i]=1;
- for(int j=1;j<=i;j++)
- f[i]=max(f[i],f[j]+1);
- }
- for(int i=n;i>=1;i--)
- {
- g[i]=1;
- for(int j=n;j>=i;j--)
- g[i]=max(g[i],g[j]+1);
- }
-
- int res=-INF;
- for(int i=1;i<=n;i++)
- res=max(res,f[i]+g[i]-1);
- cout<
-
- }
友好城市
【题目描述】
Palmia国有一条横贯东西的大河,河有笔直的南北两岸,岸上各有位置各不相同的N个城市。北岸的每个城市有且仅有一个友好城市在南岸,而且不同城市的友好城市不相同。
每对友好城市都向政府申请在河上开辟一条直线航道连接两个城市,但是由于河上雾太大,政府决定避免任意两条航道交叉,以避免事故。编程帮助政府做出一些批准和拒绝申请的决定,使得在保证任意两条航线不相交的情况下,被批准的申请尽量多。
【输入】
第1行,一个整数N(1≤N≤5000),表示城市数。
第2行到第n+1行,每行两个整数,中间用1个空格隔开,分别表示南岸和北岸的一对友好城市的坐标。(0<≤xi≤10000)
【输出】
仅一行,输出一个整数,表示政府所能批准的最多申请数。
【输入样例】
7
22 4
2 6
10 3
15 12
9 8
17 17
4 2
【输出样例】
4
- #include
- using namespace std;
- #define x first
- #define y second
- const int N=5010;
-
- typedef pair<int,int> PII;
- int f[N];
- PII p[N];
- int main()
- {
- int n;
- cin>>n;
- for(int i=1;i<=n;i++)
- {
- cin>>p[i].x>>p[i].y;
- }
- sort(p+1,p+n+1);
- for(int i=1;i<=n;i++)
- {
- f[i]=1;
- for(int j=1;j
- {
- if(p[i].y>p[j].y)f[i]=max(f[i],f[j]+1);
- }
- }
- int res=0;
- for(int i=1;i<=n;i++)
- res=max(f[i],res);
- cout<
-
- }
拦截导弹
【题目描述】
某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。
输入导弹依次飞来的高度(雷达给出的高度数据是不大于30000的正整数,导弹数不超过1000),计算这套系统最多能拦截多少导弹,如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。
【输入】
输入导弹依次飞来的高度。
【输出】
第一行:最多能拦截的导弹数;
第二行:要拦截所有导弹最少要配备的系统数。
【输入样例】
389 207 155 300 299 170 158 65
【输出样例】
6
2
- #include
- using namespace std;
- const int N=1010;
- int f[N],a[N];
- bool vis[N];
- int main()
- {
- int n=0;
- int x;
- while(cin>>x)a[++n]=x;
-
- int res=0;
-
- //求最长不上升子序列
-
- for(int i=n;i>=1;i--)
- {
- f[i]=1;
- for(int j=n;j>i;j--)
- if(a[i]>=a[j])
- f[i]=max(f[i],f[j]+1);
- res=max(res,f[i]);
- }
- cout<
-
- //求数组最少能被几个最长下降子序列全部覆盖
-
-
- int cnt=0,h=0,ans=0; //cnt是统计已经拦截的导弹
- //h每次拦截后的高度
- //ans最少导弹拦截系统
- while(cnt
- {
- ans++;
- h=30000;
- for(int i=1;i<=n;i++)
- {
- if(h>=a[i]&&!vis[i])
- {
- h=a[i]; //更新高度
- vis[i]=1; //被访问过
- cnt++;
- }
- }
- }
- cout<
-
- }
导弹防御系统
导弹防御系统【剪枝:迭代加深/全局最小值】
为了对抗附近恶意国家的威胁,RR 国更新了他们的导弹防御系统。
一套防御系统的导弹拦截高度要么一直 严格单调 上升要么一直 严格单调 下降。
例如,一套系统先后拦截了高度为 3 和高度为 4 的两发导弹,那么接下来该系统就只能拦截高度大于 44 的导弹。
给定即将袭来的一系列导弹的高度,请你求出至少需要多少套防御系统,就可以将它们全部击落。
输入格式
输入包含多组测试用例。
对于每个测试用例,第一行包含整数 nn,表示来袭导弹数量。
第二行包含 n 个不同的整数,表示每个导弹的高度。
当输入测试用例 n=0时,表示输入终止,且该用例无需处理。
输出格式
对于每个测试用例,输出一个占据一行的整数,表示所需的防御系统数量。
数据范围
1≤n≤50
输入样例:
- 5
- 3 5 2 4 1
- 0
输出样例:
2
样例解释
对于给出样例,最少需要两套防御系统。
一套击落高度为 3,4 的导弹,另一套击落高度为 5,2,1 的导弹。
- #include
- using namespace std;
-
- // 这题是拦截拦截第二问的加强版
- // 拦截导弹第二问是只考虑下降序列的方案数,因此直接用贪心搜出最优解即可(证明在那一题的笔记里)
- // 这一题,确实要考虑下降和上升两种序列的方案数
- // 因此只能用dfs进行爆搜两种方案的搭配,但无论是上升还是下降方案,依然采用上一题的贪心思路
-
- const int N = 55;
- int n;
- int a[N];
- int up[N], down[N];
- int res;
-
- //三个参数分别是考虑前u个导弹
- //已经采用了上升系统个数sum_up
- //和下降系统个数sum_down
- void dfs(int u, int sum_up, int sum_down) {
- //如果已经超过了最优解答案,那么直接剪枝
- if (sum_up + sum_down >= res) return;
- //没有超过最优解答案,且把所有导弹都考虑到了
- //那他就是当前最优解了
- if (u == n) {
- res = sum_up + sum_down;
- return;
- }
- //情况一:考虑用上升拦截系统来拦截第u个导弹
- // 上升拦截系统的贪心思路是:
- // 如果当前已有的上升拦截系统的高度都大于第u个导弹高度,则重新开一套系统
- // 否则,则由当前低于第u个导弹最高拦截系统来负责拦截
- int k = 0;
- while (k < sum_up && up[k] >= a[u]) ++k;
- //找到了有这么个拦截系统
- int t = up[k]; //t用于dfs回溯的时候恢复现场
- up[k] = a[u];
- if (k >= sum_up) dfs(u + 1, sum_up + 1, sum_down);
- else dfs(u + 1, sum_up, sum_down);
- //恢复现场
- up[k] = t;
-
- //情况二:考虑用下降拦截系统来拦截第u个导弹
- // 下降拦截系统的贪心思路是:
- // 如果当前已有的下降拦截系统的高度都小于第u个导弹高度,则重新开一套系统
- // 否则,则由当前大于第u个导弹最低拦截系统来负责拦截
- k = 0;
- while (k < sum_down && down[k] <= a[u]) ++k;
- t = down[k]; //t用于dfs回溯的时候恢复现场
- down[k] = a[u];
- if (k >= sum_down) dfs(u + 1, sum_up, sum_down + 1);
- else dfs(u + 1, sum_up, sum_down);
- //恢复现场
- down[k] = t;
- }
-
- int main() {
- while (cin >> n, n) {
- for (int i = 0; i < n; ++i) cin >> a[i];
- //最差情况是n个导弹分别用n个系统拦截
- //因此可以设置res初始为n来设立哨兵
- res = n;
- dfs(0, 0, 0);
- cout << res << endl;
- }
- return 0;
- }
最长公共上升子序列
熊大妈的奶牛在小沐沐的熏陶下开始研究信息题目。
小沐沐先让奶牛研究了最长上升子序列,再让他们研究了最长公共子序列,现在又让他们研究最长公共上升子序列了。
小沐沐说,对于两个数列 A 和 B,如果它们都包含一段位置不一定连续的数,且数值是严格递增的,那么称这一段数是两个数列的公共上升子序列,而所有的公共上升子序列中最长的就是最长公共上升子序列了。
奶牛半懂不懂,小沐沐要你来告诉奶牛什么是最长公共上升子序列。
不过,只要告诉奶牛它的长度就可以了。
数列 A 和 B 的长度均不超过 3000。
输入格式
第一行包含一个整数 N,表示数列 A,B 的长度。
第二行包含 N 个整数,表示数列 A。
第三行包含 N 个整数,表示数列 B。
输出格式
输出一个整数,表示最长公共上升子序列的长度。
数据范围
1≤N≤3000,序列中的数字均不超过 231−1。
输入样例:
- 4
- 2 2 1 3
- 2 1 2 3
输出样例:
2
朴素版(容易TLE)
-
- #include
- using namespace std;
- const int N=3010;
- int a[N],b[N],f[N][N];
- int main()
- {
- int n,ans=0;
- scanf("%d",&n);
- for(int i=1;i<=n;i++) scanf("%d",&a[i]);
- for(int i=1;i<=n;i++) scanf("%d",&b[i]);
- for(int i=1;i<=n;i++)
- for(int j=1;j<=n;j++)
- {
- f[i][j]=f[i-1][j];//所有不包含a[i]的最长公共上升子序列
- if(a[i]==b[j])//所有包含a[i]的最长公共上升子序列
- {
- f[i][j]=max(f[i][j],1);//当空的时候是自己,也就是1
- for(int k=1;k
//求最长公共上升子序列 - if(b[k]
- f[i][j]=max(f[i][j],f[i][k]+1);
- }
- }
- //求最大值,第一个序列的前n个字母,与b的匹配最大
- for(int i=1;i<=n;i++) ans=max(ans,f[n][i]);
- printf("%d\n",ans);
- return 0;
- }
优化
-
- #include
- using namespace std;
- const int N=3010;
- int a[N],b[N],f[N][N];
- int main()
- {
- int n;
- scanf("%d",&n);
- for(int i=1;i<=n;i++) scanf("%d",&a[i]);
- for(int i=1;i<=n;i++) scanf("%d",&b[i]);
- for(int i=1;i<=n;i++)
- {
- int maxv=1;//由于在k中重复求前j个最大值,所有用一个maxv记录前j个的最长上升子序列的最大值
- for(int j=1;j<=n;j++)
- {
- f[i][j]=f[i-1][j];//所有不包含a[i]的最长公共上升子序列
- if(a[i]==b[j]) f[i][j]=max(f[i][j],maxv);//所有包含a[i]的最长公共上升子序列,更新最大值
- }
- }
- //最后更新一遍最大值
- int ans=0;
- for(int i=1;i<=n;i++) ans=max(ans,f[n][i]);
- printf("%d\n",ans);
- return 0;
- }
-
-
相关阅读:
第二章、数据结构和算法9分
商业智能系统的主要功能包括数据仓库、数据ETL、数据统计输出、分析功能
CentOS 离线升级Linux的内核并删除多有内核
代码复现: VoxelNet论文和代码解析 pytorch版本(二) Dataloader.py
医学图像 开源数据整理合集1
忘记Grafana 密码怎么办 教你2种Grafana重置admin密码方法详细步骤
【hcie-cloud】【1】华为云Stack解决方案介绍、华为文档获取方式 【上】
(保姆级)服务器-Zabbix6.0使用Python脚本实现带图片的邮箱的报警
136、LeetCode-496.下一个更大元素Ⅰ
SQLite 数据库安装及使用(Linux)
-
原文地址:https://blog.csdn.net/m0_64378422/article/details/127712575