Sort an array
2010-09-25 16:11 wansishuang 阅读(260) 评论(0) 收藏 举报You are given an array of positive integers. Convert it to a sorted array with minimum cost. Only valid operation are
1) Decrement -> cost = 1
2) Delete an element completely from the array -> cost = value of element
For example:
4,3,5,6, -> cost 1
10,3,11,12 -> cost 3
Remember C(n, m) is the cost of making a[1 .. n] into a non-decreasing
sequence with the last element being no more than m.  And we always
draw m from the set V of values in a.
So here is the new DP:
C(1, m) = max(a[1] - m, 0)  // first row only decrement is possible
C(n, m) = min (
  a[n] + C(n - 1, m),   // delete
  (a[n] <= m) ?  C(n - 1, a[n]) : C(n - 1, m) + a[n] - m // decrement
)
In case you don't follow, the "//delete" line is saying that we
already know the cost of making everything up to element n-1 non-
decreasing and no more than m.  This, by recursive assumption, is just
C(n-1,m).  The additional cost of deleting a[n] is a[n].
The "//decrement" line is similar, but there are 2 cases.  If a[n] is
more than m, we must decrement it.  The cost here consists of making
everything up to n-1 non-decreasing and no more than m, i.e. C(n-1,m).
Plus we have the cost of chopping a[n] down to m, which is a[n]-m.
In the other case, a[n] is m or less.  So there's no need to
decrement, but we must get the elements a[1..n-1] to be no more than
a[n].  Again by recursive assumption this cost is C(n-1,a[n]).
Here is an example.  Suppose we have a = [5, 1, 1, 1, 3, 1].  The
least cost here is obtained by decrementing the 5 to 1 (cost 4) and
deleting the final 1 (cost 1) for a total cost of 5.
So let's try the algorithm. (You must view this with a fixed font.)
Table of C(n, m) values:
    m = 1   3   5
n = 1 : 4   2   0
n = 2 : 4   3*  1*
n = 3 : 4   4   2*
n = 4 : 4   4   3*
n = 5 : 6m  4   4
n = 6 : 6   5*  5*
Here * means C resulted from decrementing and "m" means that a
decrement was based on the value of m rather than a[n].
We take the answer from C(6,5) = 5.
Implementing this is a little tricky because m values are drawn from
V.  You could use a hash table for the m-axis.  But it's more
efficient to store V in an array and convert all the values of m in
the DP into indices of V.  Because all the indices lie in [ 1 .. |
V| ], we can use simple arrays rather than hash tables to represent
the rows of the table C.
We only need 2 rows at a time, so O(|V|) storage does the job.
For C, we also need to convert all the indices to origin 0.
So here's the final O(n^2) code.  I think this is a correct
implementation.  If anyone has an example that breaks it, I'd like to
see.
#include <stdio.h>
#define NMAX 10000
int cost(int *a, int N)
{
  int i, j, max, Nv;
  int V[NMAX], A[NMAX], B[NMAX];
  int *Cm = A, *Cn = B;  // (n-1)'th and n'th rows of C
  // Compute set V with no duplicates.
  // Remember where max element is.
  Nv = max = 0;
  for (i = 0; i < N; i++) {
    for (j = 0; j < Nv; j++)
      if (a[i] == V[j])
        break;
    if (j == Nv) {
      V[Nv++] = a[i];
      if (V[j] > V[max])
        max = j;
    }
    a[i] = j; // Convert a to indices.
  }
  // Fill in first row of C.
  for (i = 0; i < Nv; i++)
    Cm[i] = (V[a[0]] >= V[i]) ? V[a[0]] - V[i] : 0;
  // Fill in the rest of the rows of C.
  for (i = 1; i < N; i++) {
    for (j = 0; j < Nv; j++) {
      int del = Cm[j] + V[a[i]];
      int dec = (V[a[i]] <= V[j]) ? Cm[a[i]] : Cm[j] + V[a[i]] - V[j];
      Cn[j] = (del < dec) ? del : dec;
    }
    // Swap row buffers so current becomes previous.
    int *tmp = Cn;  Cn = Cm; Cm = tmp;
  }
  return Cm[max];
}
int main(void)
{
  static int a[] = { 5, 1, 1, 1, 3, 1 };
  printf("Min cost = %d\n", cost(a, sizeof a / sizeof a[0]));
  return 0;
}
 
                    
                     
                    
                 
                    
                 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号