算法做题-动态规划

2023-01-12  本文已影响0人  7cdaccb1777a

合唱队(动态规划)

描述:

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 

题解:

思路,采用的是对态规划的办法,求左边最长递增子序列和右边最长递减子序列,

父问题递归成子问题,最小子问题解是1,反递归回去可得父问题解

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 + "");

    }

}

上一篇 下一篇

猜你喜欢

热点阅读