Problem:
Blur

図 1 のような 10×10 のマス目の「布」があり、（1，2）のようにX座標・Y座標の値の対でマス目を示すことにします。座標値は 0 から始まる整数とします。例えば、図 1 の◎の座標は (1, 2) です。
この「布」に染料を少しずつたらして染物を作ります。たらす染料の滴には「大」「中」「小」の 3 サイズがあり、染料の滴の落ちたマス目を中心に図 1 のように周囲も色がつきます。図 1 で☆が中心、○が色のにじむ範囲です。

「布」は、最初は「まっしろ」つまり、どのマス目も色の濃さを示す値が 0 とします。染料の滴が落ちるごとに値が 1 ずつ増えていきます。「小」が（1, 2）、「中」が（3, 2）に落ちた場合、各マス目の値は図 2 の左のようになります。染料がもったいないので、図 2 の右に示すようなにじむ範囲が布の外にはみ出すような染料の落とし方はしないことになっています。また、同じ場所に複数の染料をたらすこともあります。

このような作業を何回か繰り返した結果、布にすばらしい模様が浮かび上がりましたが、残念なことに、うっかり作業経過を記録し忘れてしまいました。どうにもさっぱり思い出せませんが、かろうじて、落とした染料の滴数は覚えていました。あなたは、すばらしい染物を再現しなければなりません。すばらしい染物のデータを読みこんで、どこに、どのような染料をたらしたかを出力するプログラムを作成してください。なお、落とした染料の滴数は 12 以下とします。

入力

入力の形式は以下のとおりです：

最初の 1 行に落とした染料の滴数 n が与えられます。次の行から 10 行に各座標の色の濃さが空白区切りで与えられます。

出力

出力は n 行からなります。染料の滴の「大」を 3、「中」を 2、「小」を 1 で表し、落とした染料ごとに、そのX座標、Y座標、滴の大きさを空白で区切って1行に出力してください。

染料のたらし方はどのような順番で出力しても良いものとします。

入力例1

2
0 0 0 0 0 0 0 0 0 0
0 0 0 1 0 0 0 0 0 0
0 0 1 1 1 0 0 0 0 0
0 0 0 1 0 0 0 1 1 1
0 0 0 0 0 0 0 1 1 1
0 0 0 0 0 0 0 1 1 1
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0

出力例1

3 2 1
8 4 2

入力例2

6
0 0 1 0 0 0 0 0 0 0
0 1 1 1 0 0 0 0 0 0
1 1 1 1 1 1 1 1 0 0
0 1 1 1 1 1 1 1 0 0
0 0 1 1 1 3 1 1 0 0
0 0 1 1 3 1 1 1 0 0
0 0 1 1 1 1 1 1 1 0
0 0 1 1 1 1 1 1 1 1
0 0 0 0 0 0 1 1 1 0
0 0 0 0 0 0 0 1 0 0

出力例2

2 2 3
7 7 3
6 3 2
3 6 2
4 4 1
5 5 1

Solution in JAVA (judge verdict: Accepted)

import java.util.*;
import java.io.*;
import static java.lang.Math.*;

class Drop {

    static final int SMALL = 1;
    static final int MIDDLE = 2;
    static final int LARGE = 3;
    
    final int x;
    final int y;
    final int size;

    Drop ( final int x, final int y, final int size ) {
	this.x = x;
	this.y = y;
	this.size = size;
    }

    public String toString() {
	return String.format( "%d %d %d", x, y, size );
    }
}

class Main {
    
    public static void main( final String[] args ) {

	final Scanner stdin = new Scanner( System.in );

	final int n = stdin.nextInt();
	final int[][] map = new int[10][10];
	for ( int i = 0; i < 10; i++ ) {
	    for ( int j = 0; j < 10; j++ ) {
		map[i][j] = stdin.nextInt();
	    }		
	}

	Stack<Drop> answer = new Stack<Drop>();
	dfs( map, answer, n );

	for ( Drop d : answer ) {
	    System.out.println( d );
	}
    }

    static boolean hasNoDrop( final int[][] map ){
	for ( int[] rows : map ) {
	    for ( int val : rows ) {
		if ( val != 0 ) {
		    return false;
		}
	    }
	}
	return true;
    }

    static boolean finish( int[][] map, Stack<Drop> answer, final int noOfDrop ) {
	return ( noOfDrop == answer.size() && hasNoDrop( map ) );
    }

    static void printMap( int[][] map ) {
	for ( int[] rows : map ) {
	    System.err.println( Arrays.toString( rows ) );
	}
    }

    static void dfs( int[][] map, Stack<Drop> answer, final int noOfDrop ) {

	if ( noOfDrop == answer.size() ) {
	    return;
	}

	for ( int y = 0; y <= 9; y++ ) {
	    for ( int x = 0; x <= 9; x++ ) {
		if ( map[y][x] > 0 ) {
		    boolean putOnce = false;
		    
		    if ( canPutLarge( map, x, y ) ) {
			putOnce = true;
			addLarge( map, x, y, -1 );
			answer.push( new Drop( x, y + 2, Drop.LARGE ) );
			//System.err.printf( "PUT LARGE @ (%d %d)\n", x, y );
			dfs( map, answer, noOfDrop );
			if ( finish( map, answer, noOfDrop ) ) {
			    return;
			}
			addLarge( map, x, y, 1 );
			answer.pop();
		    }
		    if ( canPutMiddle( map, x, y ) ) {
			putOnce = true;
			addMiddle( map, x, y, -1 );
			answer.push( new Drop( x + 1, y + 1, Drop.MIDDLE ) );
			//System.err.printf( "PUT MIDDLE @ (%d %d)\n", x, y );
			dfs( map, answer, noOfDrop );
			if ( finish( map, answer, noOfDrop ) ) {
			    return;
			}
			addMiddle( map, x, y, 1 );
			answer.pop();
		    }
		    if ( canPutSmall( map, x, y ) ) {
			putOnce = true;
			addSmall( map, x, y, -1 );
			answer.push( new Drop( x, y + 1, Drop.SMALL ) );
			//System.err.printf( "PUT SMALL @ (%d %d)\n", x, y );
			dfs( map, answer, noOfDrop );
			if ( finish( map, answer, noOfDrop ) ) {
			    return;
			}
			addSmall( map, x, y, 1 );
			answer.pop();
		    }

		    if ( !putOnce ) {
			return;
		    }
		}
	    }
	}
    }

    static boolean canPutSmall( int[][] map, int cx, int cy ) {
	if ( 1 <= cx && cx <= 8 && cy <= 7 ) {
	    return  map[cy][cx] > 0 && map[cy + 1][cx] > 0 &&
		map[cy + 1][cx + 1] > 0 && map[cy + 1][cx - 1] > 0 && 
		map[cy + 2][cx] > 0;
	} else {
	    return false;
	}
    }
    
    static void addSmall( int[][] map, int cx, int cy, int val ) {
	map[cy][cx] += val;
	map[cy + 1][cx] += val;
	map[cy + 1][cx + 1] += val;
	map[cy + 1][cx - 1] += val;
	map[cy + 2][cx] += val;	
    }

    static boolean canPutMiddle( int[][] map, int cx, int cy ) {
	if ( cx < 8 && cy < 8 ) {
	    for ( int y = cy; y <= cy + 2; y++ ) {
		for ( int x = cx; x <= cx + 2; x++ ) {
		    if ( map[y][x] <= 0 ) {
			return false;
		    }		    
		}
	    }
	    return true;
	} else {
	    return false;
	}	    
    }
        
    static void addMiddle( int[][] map, int cx, int cy, int val ) {
	for ( int y = cy; y <= cy + 2; y++ ) {
	    for ( int x = cx; x <= cx + 2; x++ ) {
		map[y][x] += val;
	    }
	}
    }

    static boolean canPutLarge( int[][] map, int cx, int cy ) {
	if ( 2 <= cx && cx <= 7 && cy <= 5 ) {
	    return ( map[cy][cx] > 0 && map[cy + 2][cx + 2] > 0 && 
		     map[cy + 2][cx - 2] > 0 && map[cy + 4][cx] > 0 &&
		     canPutMiddle( map, cx - 1, cy + 1 ) );
	} else {
	    return false;
	}
    }    
    
    static void addLarge( int[][] map, int cx, int cy, int val ) {
	map[cy][cx] += val;
	map[cy + 2][cx - 2] += val;
	map[cy + 2][cx + 2] += val;
	map[cy + 4][cx] += val;
	addMiddle( map, cx - 1, cy + 1, val );	
    }    
}