Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Here is an <strong>O(n)</strong> time, O(1) space solution.</p> <p>Let's call an object x <em>better than</em> an object y if and only if (x is no heavier than y) and (x is no less valuable) and (x is lighter or more valuable). Call an object x <em>first-choice</em> if no object is better than x. There exists an optimal solution consisting either of two first-choice objects, or a first-choice object x and an object y such that only x is better than y.</p> <p>The main tool is to be able to iterate the first-choice objects from lightest to heaviest (= least valuable to most valuable) and from most valuable to least valuable (= heaviest to lightest). The iterator state is an index into the objects by weight (resp. value) and a max value (resp. min weight) so far.</p> <p>Each of the following steps is O(n).</p> <ol> <li><p>During a scan, whenever we encounter an object that is not first-choice, we know an object that's better than it. Scan once and consider these pairs of objects.</p></li> <li><p>For each first-choice object from lightest to heaviest, determine the heaviest first-choice object that it can be paired with, and consider the pair. (All lighter objects are less valuable.) Since the latter object becomes lighter over time, each iteration of the loop is amortized O(1). (See also searching in a matrix whose rows and columns are sorted.)</p></li> </ol> <hr> <p>Code for the unbelievers. Not heavily tested.</p> <pre><code>from collections import namedtuple from operator import attrgetter Item = namedtuple('Item', ('weight', 'value')) sentinel = Item(float('inf'), float('-inf')) def firstchoicefrombyweight(byweight): bestsofar = sentinel for x in byweight: if x.value &gt; bestsofar.value: bestsofar = x yield (x, bestsofar) def firstchoicefrombyvalue(byvalue): bestsofar = sentinel for x in byvalue: if x.weight &lt; bestsofar.weight: bestsofar = x yield x def optimize(items, maxweight): byweight = sorted(items, key=attrgetter('weight')) byvalue = sorted(items, key=attrgetter('value'), reverse=True) maxvalue = float('-inf') try: i = firstchoicefrombyvalue(byvalue) y = i.next() for x, z in firstchoicefrombyweight(byweight): if z is not x and x.weight + z.weight &lt;= maxweight: maxvalue = max(maxvalue, x.value + z.value) while x.weight + y.weight &gt; maxweight: y = i.next() if y is x: break maxvalue = max(maxvalue, x.value + y.value) except StopIteration: pass return maxvalue items = [Item(1, 1), Item(2, 2), Item(3, 5), Item(3, 7), Item(5, 8)] for maxweight in xrange(3, 10): print maxweight, optimize(items, maxweight) </code></pre>
    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