合唱队(动态规划)
描述:
N 位同学站成一排,音乐老师要请最少的同学出列,使得剩下的 K 位同学排成合唱队形。
设KK位同学从左到右依次编号为 1,2…,K ,他们的身高分别为T_1,T_2,…,T_KT1,T2,…,TK ,若存在i(1\leq i\leq K)i(1≤i≤K) 使得T_1T_{i+1}>......>T_KTi>Ti+1>......>TK,则称这KK名同学排成了合唱队形。
通俗来说,能找到一个同学,他的两边的同学身高都依次严格降低的队形就是合唱队形。
例子:
123 124 125 123 121 是一个合唱队形
123 123 124 122不是合唱队形,因为前两名同学身高相等,不符合要求
123 122 121 122不是合唱队形,因为找不到一个同学,他的两侧同学身高递减。
你的任务是,已知所有N位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形。
注意:不允许改变队列元素的先后顺序 且 不要求最高同学左右人数必须相等
数据范围: 1 \le n \le 3000 \1≤n≤3000
题解:
思路,采用的是对态规划的办法,求左边最长递增子序列和右边最长递减子序列,
![](https://img.haomeiwen.com/i5664207/0b69153b31294e51.png)
import java.util.Scanner;
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int count = in.nextInt();
int[] array = new int[count];
int i = 0;
while (i < count) {
array[i] = in.nextInt();
i++;
}
int[] arrayLeft = new int[count];
int[] arrayRight = new int[count];
Arrays.fill(arrayLeft, 1);
Arrays.fill(arrayRight, 1);
// 最长递增子序列
for (i = 0 ; i < count; i++) {
for (int j = 0 ; j < i; j++) {
if (array[i] > array[j]) {
arrayLeft[i] = Math.max(arrayLeft[i], arrayLeft[j] + 1);
}
}
}
//最长递减子序列,此处的遍历应该从右到左了,或者从左到右 array[i] < array[j]
for (i = count-1 ; i >= 0; i--) {
for (int j = count - 1 ; j >= i; j--) {
if (array[i] > array[j]) {
arrayRight[i] = Math.max(arrayRight[i], arrayRight[j] + 1);
}
}
}
int result = 0;
for (i = 0 ; i < count ; i ++ ) {
if (result < arrayLeft[i] + arrayRight[i] - 1) {
result = arrayLeft[i] + arrayRight[i] - 1;
}
}
System.out.print(count - result + "");
}
}
网友评论