Code
View Code
例题一:合唱队形【题目描述】
N位同学站成一排,音乐老师要请其中的(N-K)位同学出列,使得剩下的K位同学排成合唱队形。
合唱队形是指这样的一种队形:设K位同学从左到右依次编号为1,2,…,K,他们的身高分别为T1,T2,…,TK, 则他们的身高满足T1<...<Ti>Ti+1>…>TK(1≤i≤K)。
你的任务是,已知所有N位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形。
【输入格式】
共二行。
第一行是一个整数N(2≤N≤100),表示同学的总数。
第二行有n个整数,用空格分隔,第i个整数Ti(130≤Ti≤230)是第i位同学的身高(厘米)。
【输出格式】
一个整数,最少需要几位同学出列。
【输入样例】
8
186
186
150
200
160
130
197
220
【输出样例】
【数据规模】
对于50%的数据,保证有n≤20;
对于全部的数据,保证有n≤100。
解析最少出列,就是最多留下。
分析一下队形,其实质便是先上升再下降,不难联想到最长上升子序列与最长下降子序列。
定义状态F[0/1],F[0]表示以第i个人为结尾的最长上升子序列,F[1]表示以第i个人为结尾的最长合唱队形,F数组初值都为1,。
所以前i个人的最长合唱队形为max(F[0],F[1])。
状态转移方程:
F[0]=max(F[0],F[j][0]+1(if T>T[j]));(T如题所述,j<i)
F[1]=max(F[1],a[j][0],a[j][1]+1(if T<T[j]);
最后的答案为n-max(F[0],F[1])。
Code
View Code
例题二:导弹拦截【题目描述】
某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。
输入导弹依次飞来的高度,计算这套系统最多能拦截多少导弹,如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。
【输入格式】
1行,若干个整数。
【输出格式】
2行,每行一个整数,第一个数字表示这套系统最多能拦截多少导弹,第二个数字表示如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。
【输入样例】
389
207
155
300
299
170
158
65
【输出样例】
【数据规模】
导弹高度是≤50000的正整数,导弹个数≤100000。
注:O(n2) 100分,O(nlogn) 200分。
解析非常经典的一道线性DP题目。
先来说说O(n2)的做法:
第一问显然是在求最长不上升子序列,定义状态F表示以第i个数为结尾的最长不下降子序列。
状态转移方程:F=max(F,F[j]+1(if a<=a[j]))(a表示第i个导弹的高度,j<i)。
第二问实际上是在求最长上升子序列,证明比较麻烦,这里便不给出了,自行理解一下。
与第一问求法相同,只需要把<=改成>即可。
这种做法只有100分,考虑一下优化。
以第一问为例,观察样例,不难发现,当F的值相同时,越后面的导弹高度越高。
所以我们可以用一个d维护F值为i的序列的最后一个导弹的值,t记录当前求出的最长不上升子序列的长度,
然后在递推时判断a[d](1≤i≤t)的值,若大于等于当前导弹高度,就更新F。
第二问同理。
优化之后,虽然依旧是O(n2)的做法,但其时间复杂度却很小,足以拿到200分。
O(nlogn)的做法有很多,例如二分、线段树什么的,这里便不再给出(懒),有兴趣的可以自己尝试做做。
Code
O(n^2) 100分做法
O(n^2)优化 200分做法