Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Here's a proposed solution:</p> <pre><code>def max_result(a_): memo = {} a = list(a_) a.insert(0, 0) return min_and_max(a, 0, len(a)-1, memo)[1] def min_and_max(a, i, j, memo): if (i, j) in memo: return memo[i, j] if i == j: return (a[i], a[i]) min_val = max_val = None for k in range(i, j): left = min_and_max(a, i, k, memo) right = min_and_max(a, k+1, j, memo) for op in "*-+": for x in left: for y in right: val = apply(x, y, op) if min_val == None or val &lt; min_val: min_val = val if max_val == None or val &gt; max_val: max_val = val ret = (min_val, max_val) memo[i, j] = ret return ret def apply(x, y, op): if op == '*': return x*y if op == '+': return x+y return x-y </code></pre> <p>max_result is the main function, and min_and_max is auxiliary. The latter returns the minimum and maximum results that can be achieved by sub-sequence a[i..j].</p> <p>It assumes that maximum and minimum results of sequences are composed by maximum and minimum results of sub-sequences. Under this assumption, the problem has optimal substructure and can be solved with dynamic programming (or memoization). Run time is O(n^3).</p> <p>I haven't proved correctness, but I have verified its output against a brute force solution with thousands of small randomly generated inputs.</p> <p>It handles the possibility of a leading unary minus by inserting a zero at the beginning of the sequence.</p> <p><strong>EDIT</strong></p> <p>Been thinking a bit more about this problem, and I believe it can be reduced to a simpler problem in which all values are (strictly) positive and only operators * and + are allowed.</p> <p>Just remove all zeroes from the sequence and replace negative numbers by their absolute value.</p> <p>Furthermore, if there are no ones in the resulting sequence, the result is simply the product of all numbers.</p> <p>After this reduction, the simple dynamic programming algorithm would work.</p> <p><strong>EDIT 2</strong></p> <p>Based on the previous insights I think I found a linear solution:</p> <pre><code>def reduce(a): return filter(lambda x: x &gt; 0, map(abs, a)) def max_result(a): b = reduce(a) if len(b) == 0: return 0 return max_result_aux(b) def max_result_aux(b): best = [1] * (len(b) + 1) for i in range(len(b)): j = i sum = 0 while j &gt;= 0 and i-j &lt;= 2: sum += b[j] best[i+1] = max(best[i+1], best[j] * sum) j -= 1 return best[len(b)] </code></pre> <p>best[i] is the maximum result that can be achieved by sub-sequence b[0..(i-1)].</p> <p><strong>EDIT 3</strong></p> <p>Here's an argument in favor of the <code>O(n)</code> algorithm based on the following assumption:</p> <p>You can always achieve the maximum result with an expression of the form</p> <p><code>+/- (a_1 +/- ... +/- a_i) * ... * (a_j +/- ... +/- a_n)</code></p> <p>That is: a product of factors composed of an algebraic sum of terms (including the case of only one factor).</p> <p>I will also use the following lemmas which are easy to prove:</p> <p>Lemma 1: <code>x*y &gt;= x+y</code> for all <code>x,y</code> such that <code>x,y &gt;= 2</code></p> <p>Lemma 2: <code>abs(x_1) + ... + abs(x_n) &gt;= abs(x_1 +/- ... +/- x_n)</code></p> <p>Here it goes.</p> <p>The sign of each factor doesn't matter, since you can always make the product positive by using the leading unary minus. Hence, to maximize the product we need to maximize the absolute value of each factor.</p> <p>Setting aside the trivial case in which all numbers are zeroes, in an optimal solution no factor will be composed only of zeroes. Therefore, since zeroes have no effect inside each sum of terms, and each factor will have at least one non-zero number, we can remove all zeroes. From now on, let's assume there are no zeroes.</p> <p>Let's concentrate in each sum of terms separately:</p> <p><code>(x_1 +/- x_2 +/- ... +/- x_n)</code></p> <p>By <strong>Lemma 2</strong>, the maximum absolute value each factor can achieve is the sum of the absolute values of each term. This can be achieved in the following way:</p> <p>If x_1 is positive, add all positive terms and subtract all negative terms. If x_1 is negative, subtract all positive terms and add all negative terms.</p> <p>This implies that the sign of each term does not matter, we can consider the absolute value of each number and only use operator + inside factors. From now on, let's consider all numbers are positive.</p> <p>The crucial step, that leads to an <code>O(n)</code> algorithm, is to prove that the maximum result can always be achieved with factors that have at most 3 terms.</p> <p>Suppose we have a factor of more than 3 terms, by <strong>Lemma 1</strong> we can break it into two smaller factors of 2 or more terms each (hence, each add up to 2 or more), without reducing the total result. We can break it down repeatedly until no factors of more than 3 terms are left.</p> <p>That completes the argument. I still haven't found a complete justification of the initial assumption. But I tested my code with millions of randomly generated cases and couldn't break it.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload