facebook Hacker Cup 2012 Qualification - solution for billboards

Christian Harms's picture

The second problem from this year facebook hackercup sound like the classic knapsack problem. But the solution is much easier (words are in fixed sort order). Feel free to find a smarter algorithm or comment my python solution.

problem description

We are starting preparations for Hacker Cup 2013 really early. Our first step is to prepare billboards to advertise the contest. We have text for hundreds of billboards, but we need your help to design them.

The billboards are of different sizes, but are all rectangular. The billboard widths and heights are all integers. We will supply you with the size in inches and the text we want printed. We want you to tell us how large we can print the text, such that it fits on the billboard without splitting any words across lines. Since this is to attract hackers like yourself, we will use a monospace font, meaning that all characters are of the same width (e.g.. 'l' and 'm' take up the same horizontal space, as do space characters). The characters in our font are of equal width and height, and there will be no additional spacing between adjacent characters or adjacent rows. If you print a word on one line and print the next word on the next line, you do not need to print a space between them.

Let's say we want to print the text "Facebook Hacker Cup 2013" on a 350x100" billboard. If we use a font size of 33" per character, then we can print "Facebook" on the first line, "Hacker Cup" on the second and "2013" on the third. The widest of the three lines is "Hacker Cup", which is 330" wide. There are three lines, so the total height is 99". We cannot go any larger.

my python solution

My first step was to decide the starting fontsize. I choosed the largest word with little help of the map function and calculated the fontsize. Words will not wrapped so the largest word has to fit in the billboard width.

Then I started to put the words into the billboard. If the word does not fit into the actual line, I increased the rowCount. If all all words fit into the billboard border the fontsize is the result. If not I decreased the fontsize by 1 and started again. This sounds not optimal but solved the input set in 0.1 second.

  1. import sys
  2.  
  3. input = file(sys.argv[1])
  4.  
  5. for case in range(int(input.readline())):
  6.     words = input.readline().strip().split()
  7.     width = int(words.pop(0))
  8.     height = int(words.pop(0))
  9.  
  10.     # find starting size
  11.     fontsize = width/max(map(len, words))
  12.  
  13.     # iterate over fontsize until a result or fontsize=0
  14.     while fontsize:
  15.         col = len(words[0])
  16.         row = 0
  17.         for word in words[1:]:
  18.             if col+1+len(word) > width/fontsize:
  19.                 row += 1
  20.                 col = len(word)
  21.                 if row >= height/fontsize:
  22.                     break
  23.             else:
  24.                 col += 1+len(word)
  25.         #word check loop ended - does it fit?
  26.         if row >= height/fontsize:
  27.             fontsize -= 1  
  28.         else:
  29.             break
  30.     #while
  31.     print "Case #%d: %d" % (case+1, fontsize)
  32. input.close()

Here the test data to try the solution with python.

input data result data
5
20 6 hacker cup
100 20 hacker cup 2013
10 20 MUST BE ABLE TO HACK
55 25 Can you hack
100 20 Hack your way to the cup/pre>
Case #1: 3
Case #2: 10
Case #3: 2
Case #4: 8
Case #5: 7

top score java solution

The c++ solutions in the top 10 of the hackercup scroreboard are long and (for non-active C++ coder) not easy to read. I choosed the nr.10 entry with a java solution. He had coded many helper functions for reading input data but the solve-method looks simular my algorithm. The only change is starting with fontsize 0 and running until the words dont fit into the billboard. It depends on the fontsize and if billboard are higher than wider.

  1. public void solve() throws Exception {
  2.         int tests = iread();
  3.         for (int ntest = 1; ntest <= tests; ntest++) {
  4.                 int w = iread(), h = iread();
  5.                 String[] s = in.readLine().split(" ");
  6.                 int ans = 0;
  7.                 for (int size = 1; size <= 1000; size++) {
  8.                         int ww = w / size, hh = h / size;
  9.                         int pos = -1, line = 0, cur = 0;
  10.                         while (cur < s.length && line < hh) {
  11.                                 if (pos + 1 + s[cur].length() <= ww) {
  12.                                         pos += 1 + s[cur].length();
  13.                                         cur++;
  14.                                 } else {
  15.                                         line++;
  16.                                         pos = -1;
  17.                                 }
  18.                         }
  19.                         if (cur < s.length)
  20.                                 break;
  21.                         ans = size;
  22.                 }
  23.                 out.write("Case #"+ntest+": "+ans + "\n");
  24.         }
  25. }

third problem auction ...

Ok - the third problem will not be a blogpost on united-coders.com. I was trying to solve this problem - but I missed it. And only 22 people (of 5947 qualified coder) had submitted correct answers for all three problems and 28 correct solutions for the auction problem! You can read the solution text (not code) for this problem in an post on facebook.