Advertisement
debetimi

catsvsdogs.py

Aug 29th, 2013
44
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 4.94 KB | None | 0 0
  1. import operator
  2.  
  3. class Cell(object):
  4.  
  5.     def __init__(self, name, child, primary, secondary):
  6.         self.name = name
  7.         self.primary = primary
  8.         self.secondary = secondary
  9.         self.children = []
  10.         self.children.append(child)
  11.  
  12.     def add_child(self, req):
  13.         self.children.append(req)
  14.  
  15.     def size(self):
  16.         return len(self.children)
  17.  
  18.     def delete_from_votes(self, primary_tracker, secondary_tracker):
  19.         # if we can still make some sort of pair
  20.         # we remove ourselves form the opposite list
  21.         if self.size():
  22.             if self.name in self.secondary:
  23.                 self.secondary.pop(self.name)
  24.  
  25.         #if you are child of any other element you need to be removed
  26.         clean_up_primary = []
  27.         for k in self.primary:
  28.             item = self.primary[k]
  29.             while self.name in item.children:
  30.                 item.children.remove(self.name)
  31.             if not item.children:
  32.                 clean_up_primary.append(k)
  33.  
  34.         clean_up_secondary = []
  35.         for k in self.secondary:
  36.             item = self.secondary[k]
  37.             while self.name in item.children:
  38.                 item.children.remove(self.name)
  39.             if not item.children:
  40.                 clean_up_secondary.append(k)
  41.  
  42.         #For the primary cells remove the ones that need to be cleaned up
  43.         for vote in clean_up_primary:
  44.             self.primary.pop(vote)
  45.  
  46.         #For the secondary cells remove the one that needs to be cleaned up
  47.         #additionally, since this cell has no more children it means that all
  48.         #its higher priority children have had their places (kept/remove) set
  49.         #this means we must add this vote to list that keeps track of items
  50.         #choses from the secondary column if it no longer exists in primary column
  51.         #orhas already been chosen for the primary category
  52.         for cell in clean_up_secondary:
  53.             self.secondary.pop(cell)
  54.             if not cell in primary_tracker and not cell in self.primary:
  55.                 secondary_tracker.append(cell)
  56.  
  57.         #Finally remove yourself from this list
  58.         self.primary.pop(self.name)
  59.         return True if self.size() else False
  60.  
  61.     def __str__(self):
  62.         return str(self.children)
  63.  
  64.     def __repr__(self):
  65.         return self.__str__()
  66.  
  67. def happy_voters(votes, debug=True):
  68.  
  69.     votes_to_keep = {}
  70.     votes_to_remove = {}
  71.     num_happy = 0
  72.  
  73.     for keep, remove in votes:
  74.         if not keep in votes_to_keep:
  75.             votes_to_keep[keep] = Cell(keep, remove, votes_to_keep, votes_to_remove)
  76.         else:
  77.             votes_to_keep[keep].add_child(remove)
  78.         if not remove in votes_to_remove:
  79.             votes_to_remove[remove] = Cell(remove, keep, votes_to_remove, votes_to_keep)
  80.         else:
  81.             votes_to_remove[remove].add_child(keep)
  82.  
  83.     #Use these lists to keep track of what is unambiguously kept
  84.     #and those which are unabiguously removed
  85.     kept = []
  86.     removed = []
  87.  
  88.     while len(votes_to_keep) > 0 and len(votes_to_remove) > 0:
  89.         #Sort by length of children
  90.         #this is essential a greedy-ish algorithm
  91.         most_liked = sorted(votes_to_keep.iteritems(), key=operator.itemgetter(1),
  92.             cmp=lambda x,y: cmp(x.size(), y.size()), reverse=True)[0][0]
  93.         most_hated = sorted(votes_to_remove.iteritems(), key=operator.itemgetter(1),
  94.             cmp=lambda x,y: cmp(x.size(), y.size()), reverse=True)[0][0]
  95.         if debug: print 'kept: ', kept
  96.         if debug: print 'removed: ', removed
  97.  
  98.         #if we can satisfy more voters by keeping, then we keep the most liked
  99.         #otherwise we remove the most hated
  100.         if votes_to_keep[most_liked].size() >= votes_to_remove[most_hated].size():
  101.             if votes_to_keep[most_liked].delete_from_votes(kept, removed):
  102.                 if debug: print 'added to kept: ', most_liked
  103.                 kept.append(most_liked)
  104.         else:
  105.             if votes_to_remove[most_hated].delete_from_votes(removed, kept):
  106.                 if debug: print 'added to remove: ', most_hated
  107.                 removed.append(most_hated)
  108.     if debug: print 'final kept: ', kept
  109.     if debug: print 'final removed: ', removed
  110.     for keep, remove in votes:
  111.         if keep not in removed and remove not in kept:
  112.             if debug: print 'happy: ', (keep, remove)
  113.             num_happy += 1
  114.         else:
  115.             if debug: print 'unhappy: ', (keep, remove)
  116.     return num_happy
  117.  
  118. if __name__ == '__main__':
  119.     num_tests = int(raw_input())
  120.     results = []
  121.     debug = True
  122.     for i in range(num_tests):
  123.         votes = []
  124.         num_cats, num_dogs, num_votes = raw_input().strip().split(' ')
  125.         for j in range(int(num_votes)):
  126.             votes.append(tuple(raw_input().strip().split(' ')))
  127.         if debug: print "*******NEW*********"
  128.         results.append(happy_voters(votes, debug))
  129.     for result in results:
  130.         print result
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement