开发者

Unable to solve a homework (ACM-training)

I have no idea how to solve this: http://acm.sgu.ru/problem.php?contest=0&probl开发者_开发知识库em=311

Please help me with this one

I know it can be solved using segment tree but I don't know how


  1. Read all of the prices and set up a segment tree. For each segment, store the number and total cost of pieces whose prices lie in that segment. That's most of the problem, and the rest of this answer will be rather vague in hopes that you learn something.

  2. Handling an arrival of pieces is a straightforward O(log n)-time descent in the segment tree.

  3. Handling a purchase request is also an O(log n)-time descent followed by an update if a sale was made. The update may traverse a large amount of the segment tree and is fast only in an amortized sense – an interval should be entered if and only if there are pieces in that price range, and the running time of their removal should be charged to the arrival.


Loop per line:

  • interprete line command with parameters (ARRIVE/BUY)
  • update model (number icecreams per price), model: std::map price to quantity.
  • in case of BUY, output whether enough icecreams can be sold, selling cheapest icecreams first (first in map).


I have to say that I am not sold on segment trees as the best solution to this problem. Whether they are the "best" data structure seems to depend on the ratio of ARRIVE to BUY requests, because each time you make a sale, there is going to be quite a lot of work to update your segment tree after the removal of a segment.

What if you stored your inventory as a linked-list and each node contained the number of items for sale at a particular per-unit cost. This would make the cost of inserting and removing inventory much lower. To check whether you can make a sale you have to iterate through a while loop accumulating cost and quantity until you meet the goal or exceed the cost. The advantage here is that, if you make a sale, then the node you stop on is now the lowest cost of piece of inventory with which you want to start your next search. If you are working in a garbage collecting language you can just change the reference to the head of your list to the node you stopped on which would make for succinct code.

On an arrival of new inventory with a unit cost insertion is at worst O(n) where n is the # of arrivals you have. I think in the real world this wouldn't be a bad system because a real business would expect a high number of sales (happy) to non-sales (unhappy). Where this approach would perform poorly is if there were many people that wanted to buy almost your whole inventory but were just a little short on money to accomplish it.


I wrote this out of my head just now (15min). Only testet with 100k repeated queries from the example, and with that it takes 1s.

please comment cause it might be bullshit:

#!/usr/bin/python
import sys

class store:
    def __init__(self):
        self.sorted = [] # list of tuples (cost, amount) - sorted by cost
        # btw: sorting of tuples is by its elements, so first by element 0
        # that means it is sorted by cost, cheapest first
        self.count = 0 # the global amount of ice in store
        self.mergemap = {} # key = cost, value = tuple of (cost, amount)
        # the mergemap prevents the creation of multiple tuples per priceclass

    def request(self, n, money):
        if self.count < n:
            # if we have less ice in store than was requested -> unhappy
            return False
        pcsleft = n # we count down

        # loop through each priceclass as x
        for x in self.sorted:
            # x[0] is cost, x[1] is the amount of ice of that price in store
            if x[1] < pcsleft and x[0]*x[1] <= money:
                # we found cheap ice, but there is not enough of it
                pcsleft -= x[1]
                money -= x[0]*x[1]
            elif x[1] >= pcsleft and x[0]*pcsleft <= money:
                # theres enough cheap ice, next iteration will not occour
                pcsleft = 0
                money -= x[0]*pcsleft
            else:
                return False # the cheapest ice is too expensive
            if pcsleft == 0 and money >= 0:
                break # happy - break because for-each loop, not while
            if money < 0: # just for kicks, should never happen
                print "error"
                sys.exit(1)
        # when we have cheap enough ice, we remove ice from storage
        # we iterate through the priceclasses like before
        # but when we remove ice from one category, either the loop ends
        # or we completly deplete it  so it can be removed
        while n > 0: # subtract the bought count
            x = self.sorted[0]
            if x[1] > n: # the first priceclass has enough ice
                x[1] -= n
                self.count -= n
                return True # were happy
            elif x[1] == n:
                del(self.mergemap[x[0]]) # remove from mergemap
                self.sorted = self.sorted[1:] # completly remove priceclass
                self.count -= n
                return True
            elif x[1] < n: # 
                n -= x[1]
                self.count -= x[1]
                del(self.mergemap[x[0]])
                self.sorted = self.sorted[1:]

        return True

    def arrive(self, n, cost):
        if cost not in self.mergemap: # we dont have ice in that priceclass
            # create a new tuple, actually list, cause tuples are immutable
            x = [cost, n]
            self.sorted.append(x)
            # resort, should be fast, cause its almost entirely sorted,
            # and python has sorting magic :)
            self.sorted.sort()
            self.mergemap[cost] = x # insert into mergemap
        else:
            # just update the tuple, via its reference in the mergemap
            self.mergemap[cost][1]+=n
            self.count
        self.count += n # keep count correct
        # O(n*logn)

if __name__=='__main__':
    s = store()
    i = 0
    # we read from stdin
    for line in sys.stdin:
        #print line.strip()+" --> ",
        req, count, cost = line.split(' ') # not error tolerant
        if req == 'ARRIVE':
            s.arrive(int(count), int(cost))
        elif req == 'BUY':
            if s.request(int(count), int(cost)):
                print 'HAPPY '+str(i)
            else:
                print 'UNHAPPY '+str(i)
        i+=1
    print s.sorted # print out the left over ice

EDIT: added comments

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜