蓝桥杯刷题——合唱队形(线性DP、最长单调子序列)
题目描述:
N位同学站成一排,音乐老师要请其中的 (N−K) 位同学出列,使得剩下的 K位同学排成合唱队形。
合唱队形是指这样的一种队形:设 K位同学从左到右依次编号为 1,2…,K,他们的身高分别为 T1,T2,…,TK, 则他们的身高满足 T1<…<Ti>Ti+1>…>TK(1≤i≤K)。
你的任务是,已知所有 N位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形。
输入格式
输入的第一行是一个整数 N,表示同学的总数。
第二行有 N个整数,用空格分隔,第 i 个整数 Ti 是第 i 位同学的身高(厘米)。
输出格式
输出包括一行,这一行只包含一个整数,就是最少需要几位同学出列。
数据范围
2≤N≤100
,
130≤Ti≤230
输入样例:
8
186 186 150 200 160 130 197 220
输出样例:
4
思路:
因为这里是让我们求最少出列的同学人数,所以这里要使用左右两边的最长单调子序列来做,即算出每一个数在最中间时它的左右最长上升和下降子序列之和,最后比较哪个大即可,假设此时以第i个同学作为最中间达到的人数最多的话,那么此时也就是出列同学最少的情况,就可以算出最长上升和最长下降子序列之和sum,然后用总的同学人数减去sum即可。
AC代码:
1 import java.util.Scanner; 2 3 public class Main { 4 public static void main(String[] args) { 5 Scanner input = new Scanner(System.in); 6 int n = input.nextInt(); 7 int[] arr = new int[n]; 8 for (int i = 0; i < n; i++) { 9 arr[i] = input.nextInt(); 10 } 11 12 // 序列型 13 int[] left = new int[n + 1]; 14 int[] right = new int[n + 1]; 15 16 left[1] = 1; 17 // 求第i个数左边的最长上升子序列 18 for (int i = 2; i <= n; i++) { 19 // 默认为1 20 left[i] = 1; 21 for (int j = 1; j < i; j++) { 22 if (arr[j - 1] < arr[i - 1]) { 23 // 选出更长的那个 24 left[i] = Math.max(left[i], left[j] + 1); 25 } 26 } 27 } 28 29 right[n] = 1; 30 // 同上,最长下降子序列 31 for (int i = n - 1; i > 0; i--) { 32 // 默认为1 33 right[i] = 1; 34 for (int j = n; j > i; j--) { 35 if (arr[j - 1] < arr[i - 1]) { 36 // 选出更长的那个 37 right[i] = Math.max(right[i], right[j] + 1); 38 } 39 } 40 } 41 42 int maxv = Integer.MIN_VALUE; 43 for (int i = 1; i <= n; i++) { 44 // 这里-1,是因为前面算left和right的时候都加了1 45 // 从中间出发,讨论两边各自单调子序列之和哪个最大,即每一个数都有可能在中间 46 int temp = left[i] + right[i] - 1; 47 maxv = Math.max(maxv, temp); 48 } 49 50 System.out.println(n - maxv); 51 } 52 }