package com.interview.algorithms.dp;
/**
* Created_By: zouzhile
* Date: 4/2/14
* Time: 5:46 PM
*
* Problem URL: http://community.topcoder.com/stat?c=problem_statement&pm=1889&rd=4709
*
* In the city, roads are arranged in a grid pattern. Each point on the grid represents a corner where two blocks meet.
* The points are connected by line segments which represent the various street blocks.
* Using the cartesian coordinate system, we can assign a pair of integers to each corner as shown below.
*
* You are standing at the corner with coordinates 0,0. Your destination is at corner width,height.
* You will return the number of distinct paths that lead to your destination.
* Each path must use exactly width+height blocks.
* In addition, the city has declared certain street blocks untraversable.
* These blocks may not be a part of any path.
* You will be given a String[] bad describing which blocks are bad.
* If (quotes for clarity) "a b c d" is an element of bad,
* it means the block from corner a,b to corner c,d is untraversable.
*/
public class C12_9_AvoidRoads {
class Counter {
long count = 0;
public void increase() {
this.count ++ ;
}
public long value() {
return this.count;
}
}
private boolean[][][][] parseBlocks(String[] bad, int width, int height){
boolean[][][][] blocks = new boolean[width+1][height+1][width+1][height+1];
for(String block : bad) {
String[] points = block.split("\\s+");
//symmetrically set the bad way
blocks[Integer.parseInt(points[0])][Integer.parseInt(points[1])][Integer.parseInt(points[2])][Integer.parseInt(points[3])] = true;
blocks[Integer.parseInt(points[2])][Integer.parseInt(points[3])][Integer.parseInt(points[0])][Integer.parseInt(points[1])] = true;
}
return blocks;
}
public long numWays(int width, int height, String[] bad){
// fromX, fromY, toX, toY
boolean[][][][] blocks = parseBlocks(bad, width, height);
Counter counter = new Counter();
this.numWays(width, height, blocks, counter, 0, 0);
return counter.value();
}
public void numWays(int width, int height, boolean[][][][] blocks, Counter counter, int currentX, int currentY) {
// Each path must use exactly width+height blocks.
// This means you can walk up or right to reach destination
if(currentX > width || currentY > height)
return;
if(currentX == width && currentY == height) {
counter.increase();
} else {
if(currentY + 1 <= height && blocks[currentX][currentY][currentX][currentY+1] == false) {
// go up
numWays(width, height, blocks, counter, currentX, currentY + 1);
}
if(currentX + 1 <= width && blocks[currentX][currentY][currentX + 1][currentY] == false) {
// go right
numWays(width, height, blocks, counter, currentX + 1, currentY);
}
}
}
public long numWaysDP(int width, int height, String[] bad){
boolean[][][][] blocks = parseBlocks(bad, width, height);
//path[i][j]: save the path count from 0,0 to i,j
// path[i][j] = path[i-1][j] if no block from i-1,j~i,j + path[i][j] if no block from i,j-1~i,j
long[][] path = new long[width+1][height+1];
path[0][0] = 1;
//parsing the path[0][0] to path[0][height] and path[wight][0], when find one block, it turns to 0
for(int i = 1; i <= width; i++)
path[i][0] = blocks[i-1][0][i][0] || path[i-1][0] == 0?0:1;
for(int i = 1; i <= height; i++)
path[0][i] = blocks[0][i-1][0][i] || path[0][i-1] == 0?0:1;
for(int i = 1; i <= width; i++){
for(int j = 1; j <= height; j++){
if(!blocks[i-1][j][i][j]) path[i][j] += path[i-1][j];
if(!blocks[i][j-1][i][j]) path[i][j] += path[i][j-1];
}
}
return path[width][height];
}
}