斜率优化



/**
 * Covered Walkway
 * @author vanb
 * 
 * This problem would be pretty easy, if it weren't for the size of the data sets.
 * If the data sets were small, a simple DP solution would suffice:
 * 
 * Let best[i] be the best you can do covering A[0]..A[i]. 
 * Then best[i] = MIN{best[j] + C + (A[i]-A[j+1])^2} for j<i
 * and best[n-1] is your solution.
 * 
 * The simple solution would be to implement two loops:
 * for( int i=0; i<n; i++ ) to compute each best[i], 
 * and for( int j=0; j<i; j++ ) to find that minimum. 
 * But, that would be O(n^2), and when n can be as large as a million,
 * that's too much. 
 * 
 * This solution will use that basic concept, but we'll find a more efficient way
 * of finding that minimum.
 * 
 * Suppose we're at A[i], and we're trying to choose whether it's best to break 
 * at A[j] or A[k] (j<k<i). Note that since the input is guaranteed to be in 
 * increasing order, A[j]<A[k]<A[i]. So, we've got to compare:
 * best[j] + C + (A[i]-A[j+1])^2 to best[k] + C + (A[i]-A[k+1])^2
 * best[j] + C + A[i]^2 - 2*A[i]*A[j+1] + A[j+1]^2 to best[k] + C + A[i]^2 - 2*A[i]*A[k+1] + A[k+1]^2
 * 
 * Since C and A[i] will be the same for any j & k, then we're comparing
 * best[j] - 2*A[i]*A[j+1] + A[j+1]^2 to best[k] - 2*A[i]*A[k+1] + A[k+1]^2.
 * 
 * If we look at this as a function of A[i] (in fact, let x=A[i]), it looks like this:
 * -2*a[j+1]*x + (best[j]+a[j+1]^2) compared to -2*a[k+1]*x + (best[k]+a[k+1]^2)
 * 
 * So, for any A[i], if we want to know if splitting between A[j] and A[j+1] is better
 * than splitting between A[k] and A[k+1], then all we have to do is plug A[i] in
 * for x in this linear equation, and see which is smaller (since smaller is better).
 * 
 * But, since these are linear, we can take some shortcuts. Think of them as lines,
 * in y=mx+b form, with m(j)=-2*A[j+1], and b(j)=(best[j]+a[j+1]^2). Look at that slope (m(j)).
 * As j increases, so does A[j+1], and so that slope becomes more intensely negative. 
 * That means that, if j<k, once k becomes a better breakpoint, j will never be better again.
 * That is, if j<k and m(k)*x+b(k) < m(j)*x+b(j) for some x, 
 * then m(k)*w+b(k) < m(j)*w+b(j) for all w>x.
 * Once k becomes better, we never have to look at j again.
 * 
 * We'll maintain a linked list of breakpoints, and remember their m's and b's.
 * We'll walk forward through this list, and never have to go back. Any new 
 * breakpoint we add will have the most negative slope, so it will need to be
 * added to the end of the list. But, it may shunt off some other breakpoints.
 * So, we'll add it to the end of the list and remove any breakpoints that it 
 * shunts off. If we do that, then we won't have to go through the whole list to find
 * the minimum. Every breakpoint will either get walked over once, or shunted off once.
 * Either way, we've reduced that process of finding the minimum to O(n) prorated
 * over the entire algorithm, making the whole thing O(n).
 *  
 */

4258  Covered Walkway

你可能感兴趣的:(斜率优化)