Showing posts with label puzzles. Show all posts
Showing posts with label puzzles. Show all posts

Friday, November 14, 2008

Facebook Puzzler in Scala

An associate of mine pointed out some fun programming puzzles on Facebook. This one was interesting to me. It was interesting because I think it is poorly. Well at the very least it confused on first read. When specifying the cost/weight, if they would have just used the word 'each' in there it would have been far less confusing... Anyways, I decided to solve the problem in Scala, since I've been doing a lot more Scala programming lately. Here is my Solver:

object Solver {
def cache = new scala.collection.mutable.HashMap[(List[Int], Int), List[List[Int]]]()

/**
* Generates a list of solutions to the Diophantine inequality
* w1*x1 + w2*x2 +... wN*xN >= max
* where weights = (w1,w2,...wN)
* Each solution is a minimal solution.
* This means that if (x1,x2,...xN) is a solution
* then (x1,x2, ... ,-1 + xM , ... xN) is NOT a solution
*/
def solve(weights: List[Int], max: Int): List[List[Int]] = {
if (cache.contains((weights,max))){
return cache((weights,max))
}
if (weights.length == 1) {
return List(List(max / weights(0) + 1))
}
var all: List[List[Int]] = Nil
var a = 0
while (a * weights(0) < max) {
all = all ++ solve(weights.drop(1).toList, max - a * weights(0)).map(a :: _)
a += 1
}
val solution = (a :: weights.drop(1).map(_ * 0)) :: all
cache.put((weights,max), solution)
solution
}

/**
* For a given set of weights (w1, w2, ... wN) and costs (c1, c2, ... cN)
* This finds the solution (x1,x2,...xN) to the inequality
* w1*x1 + w2*x2 + ... wN*xN <= max that minimizes the total cost
* c1*x1 + c2*x2 + ... cN*xN
* It returns the solutions as a Tuple where the first element is
* the solution (x1,x2,...xN) and the second is the minimal total cost
*/
def optimizer(costs: List[Int], weights: List[Int], max: Int): (List[Int], Int) = {
val solutions = solve(weights, max)
var answer: List[Int] = Nil
var best = (answer, Integer.MAX_VALUE)
solutions.foreach((solution) => {
val cost = solution.zip(costs).foldLeft(0){(a,b) => a + b._1*b._2}
if (cost < best._2) {
best = (solution, cost)
}
})
best
}
}

I put in the cache for memoization purposes, but it doesn't always help. For example, with their sample input/output, the cache is useless. Anyways, I showed the problem to other smarter folks who immediately pointed out that this was a variant of the unbounded knapsack problem and that my solution uses dynamic programming.

Here's a dirty little secret about yours truly. I studied mathematics in college, not computer science. So it's always amusing for me to come across a problem like this and have people start talking about CS terms. Personally I looked it as a Diophantine equation (inequality to be more accurate.) Of course maybe if I was a CS person, then I would have written a nicer solution.

Wednesday, June 11, 2008

BASE Meeting

Last night I attended my first BASE (Bay Area Scala Enthusiasts) meeting. Organizer Dick Wall had a nice problem to solve for the attendees. The problem was to take a list of integers, and replace each element in the list with the product of all the other elements in the list. For example, if your input was (2,4,6,8) the output should be (4*6*8, 2*6*8, 2*4*8, 2*4*6) = (192, 96, 64, 48). If you want to solve the problem yourself, stop reading and come back when you are ready to read about the solutions.

There is an "obvious" brute force solution, which would be to implement the algorithm exactly as the problem is stated. This is an O(N^2) solution, not so good. You can do better by simply taking a product of all of the elements of the original list, and then replacing each member of the list with the product divided by the element. So for the example above, the product = 2*4*6*8 = 384, and thus the output should be (384/2, 384/4 , 384/6, 384/8). This is O(N) solution, and that is much better. This is the best you can do in terms of speed and space, as you only keep around one extra integer in memory (the product.) However, it doesn't always work.

The problem is when there is a zero in the list. Then the above algorithm will lead to division by zero errors. Dick pointed this out, and pointed out that there are really three casses. If there is exactly one zero, then every element in the return list will be zero, except for the one at the same index as the lone zero from the input list. If there are two or more zeroes, then every element in the return list will be zero. With that in mind, here was my solution:

def wallify(list:List[Int]):List[BigInt] ={
val one = BigInt.int2bigInt(1)
val noZeroes = list.filter(_ != 0)
if (noZeroes.length == list.length){
val prod = list.foldLeft(one){(p,e) => p*BigInt.int2bigInt(e)}
list.map(prod/_)
} else if (list.length - noZeroes.length == 1){
list.map((el) =>
if (el == 0)
noZeroes.foldLeft(one){(p,e) => p*BigInt.int2bigInt(e)}
else
0
)
} else {
list.map((el) => 0)
}
}

I had to leave early, and didn't finish my code until today. Here is the code that the group, led by Bill Venners:

def wallify(input: List[Int]): List[Long] = {
def boringCalcProduct(longInput: List[Long]): Long = {
var product = 1L
for (ele <- longInput) {
product *= ele
}
product
}

def calcProduct(input: List[Long]): Long =
// input.foldLeft(1L)(_ * _)
(1L /: input)(_ * _)

val zeroCount = input.filter(_ == 0).size
val longInput: List[Long] = input.map(ele => ele.toLong)
zeroCount match {
case 0 =>
val product = calcProduct(longInput)
longInput.map(product / _)
case 1 =>
val noZero = longInput.filter(_ != 0)
val product = calcProduct(noZero)
longInput.map(ele => if (ele == 0) product else 0)
case _ =>
input.map(ele => 0L)
}
}

Saturday, March 10, 2007

Mode Problem

I recently came across this interesting problem.

Given a list of N integers where more than half of the integers are the same, compute the mode (most common element) of the list.

When I came across the problem, the best I could immediately do was to compute the mode for any given set of numbers by putting the numbers into a heap using the frequency as the comparator. If you put the numbers in a heap like that then the mode is always at the root of the heap. It's equivalent to a heap sort, so it's a N*log(N) computation.

I knew this was not the best solution since it did not use the fact that the mode's frequency is greater than N/2. I mentioned the to my friend Chris and he figured out it was a classic Pigeonhole Principle problem.

His solution involved constructing dislike pairs of numbers. Basically you keep doing this until you can't. Eventually you won't be able to do it (because more than half of the numbers are the same) and the leftover will be the mode. Here's the code:

#include <iostream>
#include <vector>

using namespace std;

int mode(int*, int);

int main (int argc, char * const argv[]) {
    vector<int> nums;
    int n = 0;
    while (n != -999){
        cout << "Enter next number, -999 to quit" << endl;
        scanf("%d",&n);
        if (n != -999){
            nums.push_back(n);
        }
    }
    int sz = nums.size();
    int* a = new int[sz];
    for (int i=0;i<sz;i++){
        a[i] = nums[i];
    }
    cout << "Mode: " << mode(a,sz);
   
    return 0;
}

int mode(int* a, int n){
    int* b = new int[n];
    int j=0;
    for (int i=0; i<n; i++){
        if (i == j)
            b[j] = a[i];
        else if (a[i] == b[j])
            b[2*i-j] = a[i];
        else
            b[(++j)++] = a[i];
    }
    return b[j];
}

Blogged with Flock