package com.interview.algorithms.dp;
import com.interview.utils.ArrayUtil;
import java.util.*;
/**
* Created by chenting on 2014/6/26.
* You have been given a list of jewelry items that must be split amongst two people: Frank and Bob. Frank likes very expensive jewelry.
* Bob doesn't care how expensive the jewelry is, as long as he gets a lot of jewelry.
* Based on these criteria you have devised the following policy:
*
* 1) Each piece of jewelry given to Frank must be valued greater than or equal to each piece of jewelry given to Bob.
* In other words, Frank's least expensive piece of jewelry must be valued greater than or equal to Bob's most expensive piece of jewelry.
* 2) The total value of the jewelry given to Frank must exactly equal the total value of the jewelry given to Bob.
* 3) There can be pieces of jewelry given to neither Bob nor Frank.
* 4) Frank and Bob must each get at least 1 piece of jewelry.
* Given the value of each piece, you will determine the number of different ways you can allocate the jewelry to
* Bob and Frank following the above policy.
*
* For example:
* values = {1,2,5,3,4,5}
* Valid allocations are:
* Bob Frank
* 1,2 3
* 1,3 4
* 1,4 5 (first 5)
* 1,4 5 (second 5)
* 2,3 5 (first 5)
* 2,3 5 (second 5)
* 5 (first 5) 5 (second 5)
* 5 (second 5) 5 (first 5)
* 1,2,3,4 5,5
* Note that each '5' is a different piece of jewelry and needs to be accounted for separately.
* There are 9 legal ways of allocating the jewelry to Bob and Frank given the policy, so your method would return 9.
*/
public class C12_12_JewelrySplit {
static class CountedList<Key>{
Map<Key, Integer> map = new HashMap<Key, Integer>();
public void add(Key key, int count){
if(map.containsKey(key))
map.put(key, map.get(key) + count);
else
map.put(key, count);
}
public Set<Key> keySet(){
return map.keySet();
}
public Integer get(Key key){
return map.get(key);
}
public void clear(){
map.clear();
}
public void addAll(CountedList<Key> list){
for(Key key : list.keySet()){
this.add(key, list.get(key));
}
}
}
public static long find(Integer[] jevelries){
int count = 0;
jevelries = ArrayUtil.sort(jevelries);
int N = jevelries.length;
CountedList<Integer> solutions = new CountedList<Integer>();
CountedList<Integer> waitingList = new CountedList<Integer>();
solutions.add(0, 1);
for(int i = 0; i < N - 1; i ++){
for(Integer s : solutions.keySet()){
Integer key = s + jevelries[i];
waitingList.add(key, solutions.get(key));
}
for(Integer value : waitingList.keySet()){
solutions.add(value, waitingList.get(value));
count += findSum(value, i+1, jevelries) * waitingList.get(value);
}
waitingList.clear();
}
return count;
}
private static int findSum(Integer value, int n, Integer[] jevelries) {
int num = n < jevelries.length - n? n : jevelries.length - n;
int count = 0;
CountedList<Integer> solutions = new CountedList<Integer>();
CountedList<Integer> waitingList = new CountedList<Integer>();
solutions.add(0,1);
for(int i = 1; i <= num; i++){ //number of jevelries
for(int j = n; j <= n + 1; j++) //start and end of the
for(Integer s : solutions.keySet()){
int sum = s + jevelries[i];
if(sum == value) count++;
else if(sum > value) return count;
waitingList.add(sum, solutions.get(sum));
}
}
return count;
}
}