/** * 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 |