Sort an array
2010-09-25 16:11 wansishuang 阅读(253) 评论(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; }