冒泡排序的改编版本-动态规划

https://www.nowcoder.com/practice/6a33f0ce1e1649069f222e69e1d3d05f?tpId=90&tqId=30807&tPage=2&rp=2&ru=/ta/2018test&qru=/ta/2018test/question-ranking

冒泡排序的移动次数等于数组中逆序对的个数。给定任一数组,它的逆序对总数一定是固定的。那么根据题意我们需要翻转一些连续数组,那么我们求出每次翻转数组逆序对改变最大的就是我们所要的结果。整个过程可以用动态规划的思想

dp[i][j]表示前i个数总共旋转j次最多能够减少的逆序数对

dp[i][j] = max(dp[i-1][j] , before[t][i]-after[t][i]+dp[t-1][j-1])  (0<=t<i)

before[t][i]表示下标t到i之间数组翻转前的逆序对个数

after[t][i]表示下标t到i之间数组翻转后的逆序对个数

public class Main {
    public static void main(String[] args) {
            Scanner sc = new Scanner(System.in);
            int n=sc.nextInt();
            int k=sc.nextInt();
            int[] a=new int[n];
            for(int i=0;i<n;i++)
                a[i]=sc.nextInt();
            int[][]dp =new int[n+1][k+1];//表示前i个数总共旋转j次最多能够减少的逆序数对
            for(int i=2;i<=n;i++) {
                for(int j=1;j<=k;j++) {
                    int temp=Integer.MIN_VALUE;
                    for(int t=i-1;t>=1;t--) {
                        temp=Math.max(countReverseBefore(a,t-1,i-1)-countReverseAfter(a,t-1,i-1)+dp[t-1][j-1], temp);
//                        System.out.println(countReverseAfter(a,t-1,i-1));
                    }
                    dp[i][j]=Math.max(dp[i-1][j], temp);
                }
            }
            System.out.println(countReverseBefore(a,0,n-1)-dp[n][k]);
                
    }
    private static int countReverseBefore(int[] arr, int begin, int end) {
            int count = 0;
            for (int i = begin; i <= end; i++) {
                for (int j = i+1; j <= end; j++) {
                    if (arr[j] < arr[i]) count++;
                }
            }
            return count;
   }
   private static int countReverseAfter(int[] arr, int begin, int end) {
        int count = 0;
        for (int i = end; i >= begin; i--) {
            for (int j = i-1; j >=begin; j--) {
                if (arr[j] < arr[i]) count++;
            }
        }
        return count;
   }
}

 

posted @ 2019-05-18 11:24  LeeJuly  阅读(152)  评论(0)    收藏  举报