Code Jam : Watersheds

Posted on Thursday, May 06, 2010 by Anuj Mehta

Problem

Geologists sometimes divide an area of land into different regions based on where rainfall flows down to. These regions are called drainage basins.

Given an elevation map (a 2-dimensional array of altitudes), label the map such that locations in the same drainage basin have the same label, subject to the following rules.

* From each cell, water flows down to at most one of its 4 neighboring cells.
* For each cell, if none of its 4 neighboring cells has a lower altitude than the current cell's, then the water does not flow, and the current cell is called a sink.
* Otherwise, water flows from the current cell to the neighbor with the lowest altitude.
* In case of a tie, water will choose the first direction with the lowest altitude from this list: North, West, East, South.

Every cell that drains directly or indirectly to the same sink is part of the same drainage basin. Each basin is labeled by a unique lower-case letter, in such a way that, when the rows of the map are concatenated from top to bottom, the resulting string is lexicographically smallest. (In particular, the basin of the most North-Western cell is always labeled 'a'.)

Input

The first line of the input file will contain the number of maps, T. T maps will follow, each starting with two integers on a line -- H and W -- the height and width of the map, in cells. The next H lines will each contain a row of the map, from north to south, each containing W integers, from west to east, specifying the altitudes of the cells.

Output

For each test case, output 1+H lines. The first line must be of the form

Case #X:

where X is the test case number, starting from 1. The next H lines must list the basin labels for each of the cells, in the same order as they appear in the input.

Limits

T ≤ 100;

Small dataset

1 ≤ H, W ≤ 10;
0 ≤ altitudes < 10.
There will be at most two basins.

Large dataset

1 ≤ H, W ≤ 100;
0 ≤ altitudes < 10,000.
There will be at most 26 basins.



import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
/**
*
* @author anuj.mehta
*/
public class Watersheds {
private final static int UP = 1;
private final static int DOWN = 2;
private final static int LEFT = 3;
private final static int RIGHT = 4;
private final static int SELF = 5;
private static boolean basinFound = false;
private static char basinName = 'a';

public static void findFirstBasin(int[][] dirInfoMap, int curRow, int curCol, char[][] basinInfoMap)
{
int dir = dirInfoMap[curRow][curCol];
if(dir == SELF)
{
basinInfoMap[curRow][curCol] = basinName;
basinFound = true;
return;
}
switch (dir) {
case UP:
curRow--;
break;
case DOWN:
curRow++;
break;
case LEFT:
curCol--;
break;
case RIGHT:
curCol++;
}
findFirstBasin(dirInfoMap, curRow, curCol, basinInfoMap);
if(basinFound)
basinInfoMap[curRow][curCol] = basinName;
}

public static char populateBasinNames(int[][] dirInfoMap, int curRow, int curCol, char[][] basinInfoMap)
{
int dir = dirInfoMap[curRow][curCol];
switch(dir)
{
case SELF:
char name = basinInfoMap[curRow][curCol];
if(name == '\u0000')
{
basinName += 1;
basinInfoMap[curRow][curCol] = basinName;
return basinName;
}
else
return name;
case UP:
curRow--;
break;
case DOWN:
curRow++;
break;
case LEFT:
curCol--;
break;
case RIGHT:
curCol++;
}
return populateBasinNames(dirInfoMap, curRow, curCol, basinInfoMap);
}

/**
* @param args
*/
public static void main(String[] args) {
try {
BufferedReader br = new BufferedReader(new FileReader("Test.txt"));
int numOfMaps = Integer.parseInt(br.readLine());
for(int i =0; i < numOfMaps; i++)
{
basinName = 'a';
String[] elevationMapDimensions = br.readLine().split(" ");
int height = Integer.parseInt(elevationMapDimensions[0]);
int width = Integer.parseInt(elevationMapDimensions[1]);
int[][] elevationMap = new int[height][width];
int[][] dirInfoMap = new int[height][width];
//Store the altitude data in array
for(int j = 0; j < height; j++)
{
String[] altitudeData = br.readLine().split(" ");
for(int k = 0; k < width; k++)
{
elevationMap[j][k] = Integer.parseInt(altitudeData[k]);
}
}

//Now process array elements
for(int j =0; j < height; j++)
{
for(int k =0; k < width; k++)
{
int target = elevationMap[j][k];
int left = -1, right = -1, up = -1, down = -1;

//get neighbours
if(k-1 >= 0)
left = elevationMap[j][k-1];
if(k +1 < width)
right = elevationMap[j][k+1];
if(j-1 >= 0)
up = elevationMap[j-1][k];
if(j +1 < height)
down = elevationMap[j+1][k];
int small = target;
int direction = SELF;
if(up != -1 && up < target)
{
small = up;
direction = UP;
}
if( left != -1 && left < target )
{
if(small == -2)
{
small = left;
direction = LEFT;
}
else if(left < small)
{
small = left;
direction = LEFT;
}
}
if( right != -1 && right < target )
{
if(small == -2)
{
small = right;
direction = RIGHT;
}
else if(right < small)
{
small = right;
direction = RIGHT;
}
}
if( down != -1 && down < target )
{
if(small == -2)
{
small = down;
direction = DOWN;
}
else if(down < small)
{
small = down;
direction = DOWN;
}
}
dirInfoMap[j][k] = direction;
}
}

char[][] basinInfoMap = new char[height][width];
int curRow = 0, curCol = 0;
basinFound = false;
//first find the first basin
findFirstBasin(dirInfoMap, curRow, curCol, basinInfoMap);
if(basinFound)
basinInfoMap[curRow][curCol] = basinName;
for(int row = 0; row < height; row++)
{
for(int col = 0; col < width; col++)
{
//populate rest of the basin info
char name = populateBasinNames(dirInfoMap, row, col, basinInfoMap);
basinInfoMap[row][col] = name;
}
}

for(int j = 0; j < height; j++)
{
for(int k = 0; k < width; k++)
System.out.print(basinInfoMap[j][k] + "\t");
System.out.println();
}
System.out.println("================================");
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (NumberFormatException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}

}

0 Responses to "Code Jam : Watersheds":