Showing posts with label code jam. Show all posts
Showing posts with label code jam. Show all posts

Sunday, May 9, 2010

Code Jam 2010: Theme Park

The problem definition could be found at Code Jam web site.

Official Contest Analysis could be found at Code Jam web site.

My solution is published below.

Main functions:
  • public solve - high-level problem solving
  • private solve - low -level problem solving
  • calculateByMap - calculates euros based on ride cache

Helper classes:
  • Key - ride cache key
  • Value - ride cache value

public class ThemePark {
...
private Scanner scanner;
private PrintWriter writer;

public ThemePark(InputStream is, OutputStream os) {
scanner = new Scanner(is);
writer = new PrintWriter(os);
}
...
/**
* Solve the problem
*/

public void solve() {
int t = scanner.nextInt();

for (int i = 1; i <= t; i++) {
writer.print("Case #");
writer.print(i + ": ");

// 1 <= R <= 10^8
long r = scanner.nextInt();

// 1 <= k <= 10^9
long k = scanner.nextInt();

// 1 <= N <= 1000
int n = scanner.nextInt();

// 1 <= g[i] <= 10^7
long g[] = new long[n];
for (int j = 0; j < n; j++)
g[j] = scanner.nextInt();

writer.println(solve(r, k, g));
}
}

private String solve(long r, long k, long g[]) {
Queue<Long> queue = new LinkedList<Long>();
Queue<Long> ride = new LinkedList<Long>();

// queue, ride -> count, euros
Map<Key, Value> map = new LinkedHashMap<Key, Value>();

for (int i = 0; i < g.length; i++)
queue.add(g[i]);

BigInteger euros = new BigInteger("0");
for (int i = 0; i < r; i++) {
long sum = 0;
ride.clear();

while ((queue.size() > 0) && (sum + queue.peek() <= k)) {
ride.add(queue.peek());
sum += queue.poll();
}

// prepare key->value pair for caching...
Key key = new Key(queue.toString(), ride.toString());
Value value = new Value(ride.size(), sum);

if (!map.containsKey(key)) {
map.put(key, value);

euros = euros.add(new BigInteger(((Long) sum).toString()));
queue.addAll(ride);
} else {
// the same [ride, queue] found in cache
// so calculate euros based on cache
euros = euros.add(calculateByMap(map, key, r - i));
break;
}
}
return euros.toString();
}

private BigInteger calculateByMap(Map<Key, Value> map, Key key, long ridesLeft) {
long storedSum = 0;
boolean found = false;
int foundIndex = 0;

long remainder = 0;
long remainderSum = 0;

for (Key storedKey : map.keySet()) {
// if item found - calculate remainder
if ((!found) && (storedKey.equals(key))) {
found = true;
remainder = ridesLeft % (map.size() - foundIndex);
}
if (found) {
// calculate stored sum
storedSum += map.get(storedKey).getSum();

// calculate remainder
if (remainder > 0) {
remainderSum += map.get(storedKey).getSum();
remainder--;
}
} else
foundIndex++;
}
long storedCount = map.size() - foundIndex;
long mult = ridesLeft / (storedCount);
mult = mult * storedSum + remainderSum;
return new BigInteger(((Long) mult).toString());
}

class Key {
private String queue;
private String ride;

Key(String queue, String ride) {
this.queue = queue;
this.ride = ride;
}

public String getQueue() {
return queue;
}

public String getRide() {
return ride;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;

Key key = (Key) o;

if (!queue.equals(key.queue)) return false;
if (!ride.equals(key.ride)) return false;

return true;
}

@Override
public int hashCode() {
int result = queue.hashCode();
result = 31 * result + ride.hashCode();
return result;
}
}

class Value {
private int size;
private long sum;

Value(int size, long sum) {
this.size = size;
this.sum = sum;
}

public int getSize() {
return size;
}

public long getSum() {
return sum;
}
}
}

See also other posts in Code Jam

Code Jam 2010: Fair Warning

The problem definition could be found at Code Jam web site.

Official Contest Analysis could be found at Code Jam web site.

My solution is published below.

Main functions:
  • public solve - high-level problem solving
  • private solve - low -level problem solving

public class FairWarning {
...
private Scanner scanner;
private PrintWriter writer;

public FairWarning(InputStream is, OutputStream os) {
scanner = new Scanner(is);
writer = new PrintWriter(os);
}
...
/**
* Solve the problem
*/

public void solve() {
int c = scanner.nextInt();

for (int i = 1; i <= c; i++) {
writer.print("Case #");
writer.print(i + ": ");

// 2 <= N <= 1000
int n = scanner.nextInt();

// 1 <= t[i] <= 10^50
// collect t[i] into a TreeSet to have them sorted
NavigableSet<BigInteger> t = new TreeSet<BigInteger>();
for (int j = 0; j < n; j++)
t.add(new BigInteger(scanner.next()));

writer.println(solve(t));
}
}

private BigInteger solve(NavigableSet<BigInteger> t) {
// find GCD of all differences between
Iterator i = t.descendingIterator();
BigInteger prev = null;
BigInteger div = null;
while (i.hasNext()) {
if (prev == null)
prev = (BigInteger) i.next();
else {
BigInteger diff = prev.subtract((BigInteger) i.next()).abs();
if (diff.equals(BigInteger.ZERO))
continue;
if (div == null)
div = diff;
else
div = div.gcd(diff);
}
}

// calculate slarboseconds
BigInteger mod = prev.mod(div);
if (mod.equals(BigInteger.ZERO))
return BigInteger.ZERO;
return div.subtract(mod);
}
}

See also other posts in Code Jam

Code Jam 2010: Snapper Chain

The problem definition could be found at Code Jam web site.

Official Contest Analysis could be found at Code Jam web site.

Dynamic programming could be used:
  1. state[j] - state of j-Snapper
  2. power[j] - is j-Snapper powered
  3. power[j+1] - do we have power after j-Snapper
  4. state[i][j] - state of j-Snapper after i-snaps
  5. power[i][j] - is j-Snapper powered after i-snaps
  6. state[i][j] = (power[i-1][j]) ? !state[i-1][j] : state[i-1][j]
  7. power[i][j+1] = power[i][j] && state[i][j]

state[i][j], where i-rows, j-columns
0 0 0 0 0 0 0 0 0 0 0
1 1 0 0 0 0 0 0 0 0 0
2 0 1 0 0 0 0 0 0 0 0
3 1 1 0 0 0 0 0 0 0 0
4 0 0 1 0 0 0 0 0 0 0
5 1 0 1 0 0 0 0 0 0 0
6 0 1 1 0 0 0 0 0 0 0
7 1 1 1 0 0 0 0 0 0 0
8 0 0 0 1 0 0 0 0 0 0
9 1 0 0 1 0 0 0 0 0 0
10 0 1 0 1 0 0 0 0 0 0
11 1 1 0 1 0 0 0 0 0 0
12 0 0 1 1 0 0 0 0 0 0
13 1 0 1 1 0 0 0 0 0 0
14 0 1 1 1 0 0 0 0 0 0
15 1 1 1 1 0 0 0 0 0 0
16 0 0 0 0 1 0 0 0 0 0

power[i][j], where i-rows, j-columns
0 1 0 0 0 0 0 0 0 0 0 0
1 1 1 0 0 0 0 0 0 0 0 0
2 1 0 0 0 0 0 0 0 0 0 0
3 1 1 1 0 0 0 0 0 0 0 0
4 1 0 0 0 0 0 0 0 0 0 0
5 1 1 0 0 0 0 0 0 0 0 0
6 1 0 0 0 0 0 0 0 0 0 0
7 1 1 1 1 0 0 0 0 0 0 0
8 1 0 0 0 0 0 0 0 0 0 0
9 1 1 0 0 0 0 0 0 0 0 0
10 1 0 0 0 0 0 0 0 0 0 0
11 1 1 1 0 0 0 0 0 0 0 0
12 1 0 0 0 0 0 0 0 0 0 0
13 1 1 0 0 0 0 0 0 0 0 0
14 1 0 0 0 0 0 0 0 0 0 0
15 1 1 1 1 1 0 0 0 0 0 0
16 1 0 0 0 0 0 0 0 0 0 0

But this idea requires 30 x 10^8 array which is not possible.
If we check state[i][j] then we could find that it is just binary representation of i-number. So are not required to store it.
power[i][j+1] could be calculated only based on state[i][j].

My solution is published below.

Main functions:
  • solve - solves the problem
  • snapper - returns power after j-Snapper after i-snaps

public class SnapperChain {
...
private Scanner scanner;
private PrintWriter writer;

public SnapperChain(InputStream is, OutputStream os) {
scanner = new Scanner(is);
writer = new PrintWriter(os);
}
...
private static final int MAX_SNAPPER = 30;

/**
* Solve the problem
*/

public void solve() {
int t = scanner.nextInt();

for (int i = 1; i <= t; i++) {
writer.print("Case #");
writer.print(i + ": ");

// The light is plugged into the Nth Snapper.
// 1 <= N <= 30;
int n = scanner.nextInt();

// I have snapped my fingers K times
// 0 <= K <= 10^8;
long k = scanner.nextInt();

boolean light = snapper(n, k);
writer.println((light) ? "ON" : "OFF");
}
}

private boolean snapper(int n, long k) {
boolean[] power = new boolean[MAX_SNAPPER + 1];

power[0] = true;
for (int j = 0; j < MAX_SNAPPER; j++) {
boolean state = ((k >> j) & 0x01) == 0x01;
power[j + 1] = power[j] && state;
}
return power[n];
}
}

See also other posts in Code Jam

Code Jam 2010: Qualification Round - Solutions & Analysis

Solutions & Analysis of problems from Qualification Round of Google Code Jam 2010 could be found below
http://code.google.com/codejam/contests.html

Saturday, May 8, 2010

Code Jam 2010: Qualification Round

Today I took part in Qualification Round of Google Code Jam 2010.
Successfully solved all problems with Small datasets.
Now I'm waiting for the end of the contest to verify my solutions with Large datasets.



I plan to publish my solutions later...

Sunday, April 11, 2010

Google Code Jam: Egg Drop Solution

The problem definition could be found at Code Jam web site.

Dynamic programming:
  1. The main idea is to understand dependency between current drop and next/prev drops.
  2. Let F(D, B) - function returning Fmax number of floors in a building when Solvable(F, D, B) is true.
  3. Let do a drop. We know the result for this drop: egg has been dropped or egg has not been dropped. So we covered +1 floor. Now we have D-1 drops left.
  4. If egg has not been dropped then we still have B breaks left and for all floors from 1 to current egg will not be dropped as well. To get value of Fmax we only need to estimate how many floors upstairs we could cover to have Solvable(F, D, B) as true. We could think that we are on the ground and required value could be evaluated by F(D-1, B).
  5. If egg has been dropped then we have B-1 breaks left. The situation below current floor is still unknown but to estimate how many floors downstairs we could cover and have Solvable(F, D, B) as true we could use F(D-1, B-1).
  6. Taking all above into an account we have F(D, B) = 1 + F(D-1, B) + F(D-1, B-1)
Implementation:
  1. Next facts could help to have efficient implementation.
  2. F(D, 1) = D - because to have Solvable(F, D, B) = true we should start from 1-st floor and continue dropping from next floor one by one.
  3. F(1, B) = 1 - because to have Solvable(F, D, B) = true we should start from 1-st floor and no more drops left after first attempt.
  4. F(x, x) = 2^x -1 - because to have Solvable(F, D, B) = true and to have optimal solution we should use divide and conquer approach
  5. F(x, y) = F(x, x), for all y > x - the same as for (4) and more possible breaks don't affect the result.
  6. We need to calculate F(D, B) only for B=1..32, because all other values could be evaluated by (5) or will be -1, because they will be greater then 2^32 (4294967296)
  7. It is enough to have array[1..Z][1..32], where F(Z, 2) > 4294967296 values to have fast, cache-based implementation of F(D, B).
    (I don't know how to calculate Z theoretically, but practically Z=10000 is not enough and Z=100000 is enough)

F(D, B) - Illustration of facts discussed above


My solution is published below.

Main functions:
  • solve - solves the problem
  • initFCache - inits F-cache
  • getF - gets Fmax from F-cache
  • getD - gets Dmin based on F-cache
  • getB - gets Bmin based on F-cache

public class EggDrop {
...

private Scanner scanner;
private PrintWriter writer;

public EggDrop(InputStream is, OutputStream os) {
scanner = new Scanner(is);
writer = new PrintWriter(os);
}
...

private static final long MAX_F_VALUE = 4294967296l;
private static final int LARGE_F_VALUE = -1;
private static final int MAX_B_INDEX = 32;

private static final int F_CACHE_SIZE = 100000;
private long[][] fCache;

/**
* Solve the problem
*/

public void solve() {
fCache = new long[F_CACHE_SIZE][MAX_B_INDEX];
initFCache();

int n = scanner.nextInt();

for (int i = 1; i <= n; i++) {
// int is enough to store all numbers
// see Integer.MAX_VALUE, 2,000,000,000 < 2,147,483,647
int F = scanner.nextInt();
int D = scanner.nextInt();
int B = scanner.nextInt();

writer.print("Case #");
writer.print(i + ": ");

long Fmax = getF(D, B);
int Dmin = getD(F, B, D);
int Bmin = getB(F, D, B);

writer.printf("%1$d %2$d %3$d\n", Fmax, Dmin, Bmin);
}
}

/**
* Get Fmax from F cache
*
* @param d D
* @param b B
* @return Fmax
*/

private long getF(int d, int b) {
if (b > MAX_B_INDEX)
b = MAX_B_INDEX;

if (b == 1)
return d;

if (d > F_CACHE_SIZE)
return -1;

return fCache[d - 1][b - 1];
}

/**
* Get Dmin based on F cache
*
* @param f F
* @param b B
* @param dMax D
* @return Dmin
*/

private int getD(long f, int b, int dMax) {
for (int d = 1; d <= dMax; d++) {
long maxF = getF(d, b);
if ((maxF == LARGE_F_VALUE) || (maxF >= f))
return d;
}
throw new IllegalStateException(String.format("D not found, F=%1$d, B=%2$d, Dmax=%3$d", f, b, dMax));
}

/**
* Get Bmin based on F cache
*
* @param f F
* @param d D
* @param bMax B
* @return Bmin
*/

private int getB(long f, int d, int bMax) {
for (int b = 1; b <= bMax; b++) {
long maxF = getF(d, b);
if ((maxF == LARGE_F_VALUE) || (maxF >= f))
return b;
}
throw new IllegalStateException(String.format("B not found, F=%1$d, D=%2$d, max B=%3$d", f, d, bMax));
}

/**
* Init F cache. DP.<BR>
* F(D, B) = F(D-1, B) + 1 + F(D-1, B-1)<BR>
* if F(D, B) > 4294967296 then F(D, B) = -1
*/

private void initFCache() {
Arrays.fill(fCache[0], 1);

for (int d = 1; d < F_CACHE_SIZE; d++) {
fCache[d][0] = d + 1;
for (int b = 1; b < MAX_B_INDEX; b++) {
if ((fCache[d - 1][b] == LARGE_F_VALUE) || (fCache[d - 1][b - 1] == LARGE_F_VALUE))
fCache[d][b] = LARGE_F_VALUE;
else {
fCache[d][b] = fCache[d - 1][b] + 1 + fCache[d - 1][b - 1];
if (fCache[d][b] >= MAX_F_VALUE)
fCache[d][b] = LARGE_F_VALUE;
}
}
}
}
}

See also other posts in Code Jam