Problem description
Source: topcoder SRM 627 div2 bubblesortwithreversals
Given the array to be sorted A, after a non-Intersecting sub-array with a maximum of k a is reversed, A is sorted by bubble. What is the minimum number of swap times? The pseudocode for Bubble Sorting is as follows:
Bubblesort ():
Loop Len (a)-1 times:
For I from 0 to Len (a)-2:
If (A [I]> A [I + 1])
Swap (A [I], a [I + 1])
Problem Analysis
First, it is easy to analyze and obtain: For any array to be sorted, the number of swap requests required for Bubble Sorting = the number of reverse pairs in. This is because the Bubble sorting process is used to determine whether the two elements are in reverse order (that is, the small elements are placed behind the large elements) for any two elements. If the two elements are in reverse order, swap. The conclusion above is obvious.
[Idea 1]Next, the problem is to find the minimum value of the reverse logarithm of a given array after the reverse is at most K sub-arrays. Given an array A, it is relatively simple to solve the reverse logarithm. You can directly judge and count two for loops. The problem is hard to allow a reverse Up to K sub-arrays, so we need to consider reverse 0, 1, 2 ,..., k sub-array. If we consider the reverse K (0 = <k <= k) Sub-array, we also need to find the K sub-array, reverse, and then calculate the reverse logarithm, this situation is much more complicated, and it is difficult to clarify the clues. It seems that this road is hard to get through.
[Idea 2]We realized that this is a typical optimization problem. Dynamic Planning for complex optimization problems is an artifact. Let's try it. Dynamic Planning must meet two conditions: (1)Overlapping subproblemsThat is, some smaller subproblems will be solved repeatedly in the process of solving the optimal solution; (2)Optimal sub-structureThat is, the optimal solution of the current problem can be obtained through the optimal solution of its subproblems.
Considering that the number of backward logarithm = subscript I contributed by subscript J satisfies the requirements of I <J & A [I]> A [J], that is, the number of elements before J and in a [J] descending order. It is easy to see that the sorting of elements before subscript J does not affect the inverse logarithm of contribution of subscript J, because no matter how the elements before subscript J are sorted, the number of elements greater than a [J] does not change. Define a subproblem f (x, k) to indicate the inverse logarithm contributed by all subscripts J greater than X after a maximum of K non-overlapping subarrays are reverse, that is, \ [F (x, k) = \ sum _ {J >=x} ^ {n} contribution (J ), with \ revserse \ at \ most \ K \ disjoint \ subarrays \] Then f (0, k) indicates that after a maximum of K reverse subarrays are not overlapped, the reverse logarithm composed of all elements j> = 0 is the solution of the original problem.
[1] Base case: F (n, k) = 0, K = 0, 1,..., K, because there is no subscript greater than or equal to n. There are two scenarios,
[2] The subarray of reverse does not contain X: At this time, the value of f (x, k) is equal to the reverse logarithm with X contribution + Y (Y> = x + 1) the reverse logarithm of contribution. Because the reverse array does not contain X, the subarray before X does not affect the reverse logarithm of X contribution regardless of the reverse, therefore, the reverse subarray can have a maximum of K subarrays after X, and \ [F (x, K) = contribution (x) + f (x + 1, k) \]
[3] The subarray of reverse contains x: now we only need to consider the subarray of reverse from X (why? In other cases, we can convert it to this situation). Suppose we reverse the sub-array (A [X], a [x + 1],... A [Y-1], a [y]) to get the sub array (A [Y], a [Y-1],..., A [x + 1], a [x]), we need to calculate all contribution (J), x <= j <= y. to calculate contribution (J), we can take the sub-array B = (a [0], a [1],..., A [X],... A [y]), calculate contribution (j) in B ). Then the problem is converted to the reverse logarithm of the reverse (k-1) subarray after the array after Y + 1 (because a reverse has been used), that is, \ [F (x, k) = \ sum _ {J >=x} ^ {y} contribution (j) + f (y + 1, k-1) \] traversing y = x + 1 ,..., for each value of N, take the minimum f (x, k) in all cases ).
[4] select the minimum f (x, k) in [2] and [3 ).
Program source code
After the above analysis, we can use the bottom to up method to provide the following source code:
1 #include <iostream> 2 #include <string> 3 #include <vector> 4 #include <map> 5 #include <set> 6 #include <algorithm> 7 #include <functional> 8 #include <cstdio> 9 #include <cstdlib>10 using namespace std;11 12 // nSwap == nNiXuNumber13 class BubbleSortWithReversals14 {15 public:16 // return the number of nixu with index >= x17 int getCurNiXuNumber(vector<int> A, int x)18 {19 int n = A.size();20 int cnt = 0;21 for (int i = x; i < n; ++i)22 {23 for (int j = 0; j < i; ++j)24 {25 if (A[j] > A[i])26 {27 cnt++;28 }29 }30 }31 32 return cnt;33 }34 35 // DP solution:36 // Define: f(x, k) = the number of nixu with indices i >= x that can reverse37 // at most k subarray without overlap, thea number of xinu at index i,38 // is the number of index j with j < i && A[j] > A{i]39 //40 // Then the f(0, K) is the answer of original problem41 //42 // Base Case: f(n, k) = 0 with k = 0, 1, 2, ... MAX_K;43 // Recursive relationship:44 // Case 1: A[x] is not in the reversed subarray, which means A[x] stays in index45 // x after the most k reverses of subarray, Note that the order of elems46 // A[j] with j < x do not affect the the number of Nixu at index x47 // So in this case48 // f(x, k) = The number of nixu at index x + f(x + 1, k)49 // Case 2: A[x] is in the reversed subarray, we only need to consider the reversed 50 // subarray (A[x], A[x+1], ..., A[y-1], A[y]), cause if the reversing 51 // start before index x such as (A[a], A[b], A[c], A[x], ...), then when52 // x = a, it equals exactly the situation of current time53 // So in this Case:54 // We first revere (A[x], A[x+1], ..., A[y-1], A[y]) to obtain55 // (A[0],...A[x-1], A[y], A[y-1], ..., A[x+1], A[x])56 // Then we caculate The number of nixu at index x + f(y+1, k-1)57 // f(x, k) = the number of nixu at x + f(y + 1, k - 1);58 // Compare case 1 and case 2 to get the minimum59 60 61 int getMinSwaps(vector<int> A, int K)62 {63 int n = A.size();64 int f[MAX_K][MAX_K] = {0}; 65 // init66 for (int k = 0; k < MAX_K; ++k) f[n][k] = 0;67 68 //69 for (int x = n - 1; x >= 0; --x)70 {71 for (int k = 0; k <= K; ++k)72 {73 // Case 1: x not in the reversed subarray74 vector<int> B1(A.begin(), A.begin() + x + 1);75 f[x][k] = getCurNiXuNumber(B1, x) + f[x+1][k];76 77 // Case 2: x in the reversed subarray78 if (k >= 1)79 {80 for (int y = x + 1; y < n; ++y)81 {82 vector<int> B2(A.begin(), A.begin() + y + 1);83 reverse(B2.begin() + x, B2.begin() + y + 1);84 f[x][k] = min(f[x][k],85 getCurNiXuNumber(B2, x) + f[y+1][k-1]);86 }87 }88 }89 }90 91 return f[0][K];92 }93 public:94 static const int MAX_K = 51;95 };Complexity Analysis
The time complexity of the subfunction to obtain the current reverse logarithm is O (n ^ 2), and the outer ring of the primary function is NK times. For Case 1, only the contribution at X needs to be calculated, therefore, the subfunction complexity here is O (n). For Case 2, The subfunction needs to be calculated in X ,..., Y contribution, and I (x <= I <= y) must be cyclically, the complexity is $ \ sum _ {Y = x + 1} ^ {Y <n} \ sum _ {I = x} ^ {y} I = O (N ^ 2) $, so the total time complexity is O (NK ^ 3) When case2 occurs ).
References
[1] topcoder editorial SRM 627
[2] Dynamic Programming