Problem:
Problem F: Line Puzzle

プログラミングでパズルを解いてみよう。

n × n の数字が格子状に並んでいる。数字のいくつかは丸で囲まれており、これらを起点と呼ぶことにする。パズルのルールは以下のとおりである：

各起点から縦・横に進む１本の線を引く（斜めには引けない）。

通った数字の和が起点の数字と同じになるように線を伸ばす。

線は枝分かれしてはいけない。

線はすでに引かれた数字を通ることはできない（線は交差してはいけない）。

線は２個以上の起点を通ることはできない。

下図に示すように、パズルのゴールはすべての起点を使い、すべての数字に線を引くことである。

あなたの仕事は、パズルを解くプログラムを作成することである。
ただしこの問題では、与えられたパズルが解けるものかどうかを判定するだけでよい。

Input

入力は複数のデータセットからなる。各データセットの形式は以下のとおりである：

n
n × n の数字

n × n の数字が与えられるパズルを示し、起点の数字は負の数として与えられる。

n が 0 のとき入力の終わりを示す。

n は 3 以上 8 以下、起点以外の数字は 1 以上 50 以下、起点は -50 以上 -1 以下であると仮定してよい。また、入力されるパズルの性質として以下のことを仮定してよい：

与えられるパズルの各行、各列には最低でも１つの起点がある。

起点の個数は、全体の数字の個数 (n × n) の 20 % から 40 % 程度である。

Output

各データセットに対して、パズルが解けるものであれば "YES" を、そうでなければ "NO" と１行に出力せよ。

Sample Input

3
-3 1 1
2 -4 1
2 1 -1
3
-4 1 1
1 1 -6
1 -5 3
4
-8 6 -2 1
2 -7 -2 1
1 -1 1 1
1 1 1 -5
6
2 2 3 -7 3 2
1 -10 1 1 3 2
2 6 5 2 -6 1
3 4 -23 2 2 5
3 3 -6 2 3 7
-7 2 3 2 -5 -13
6
2 2 3 -7 3 2
1 -10 1 1 3 2
2 6 5 2 -6 1
3 4 -23 2 2 5
3 3 -6 2 3 7
-7 2 3 2 -5 -12
0

Output for the Sample Input

YES
NO
NO
YES
NO

Solution in JAVA (judge verdict: Accepted)


import java.io.IOException;
import java.util.Scanner;

public class Main {

	public static void main(String[] args) throws IOException {

		new Main().run();
	}

	private void run() throws IOException {
		Scanner scanner = new Scanner(System.in);
		while (true) {
			n = scanner.nextInt();
			if (n == 0)
				break;
			map = new int[n][n];
			v = new boolean[n][n];
			m = 0;
			p = new int[2][n * n];
			int sum = 0;
			for (int i = 0; i < n; i++)
				for (int j = 0; j < n; j++) {
					map[i][j] = scanner.nextInt();
					sum += map[i][j];
					if (map[i][j] < 0) {
						p[0][m] = i;
						p[1][m++] = j;
						v[i][j] = true;
					}

				}
			if (sum != 0) {
				System.out.println("NO");
				continue;
			}
			System.out
					.println(slove(p[0][0], p[1][0], 0, map[p[0][0]][p[1][0]]) ? "YES"
							: "NO");

		}
	}

	private boolean slove(int y, int x, int k, int sum) {
		if (sum > 0)
			return false;
		if (sum == 0) {
			if (++k == m)
				return true;
			return slove(p[0][k], p[1][k], k, map[p[0][k]][p[1][k]]);
		}
		for (int[] mo : move) {
			int ny = y + mo[0];
			int nx = x + mo[1];
			if (!isOK(ny, nx))
				continue;
			if (v[ny][nx])
				continue;
			v[ny][nx] = true;
			if (slove(ny, nx, k, sum + map[ny][nx]))
				return true;
			v[ny][nx] = false;
		}

		return false;
	}

	private boolean isOK(int ny, int nx) {
		return 0 <= ny && ny < n && 0 <= nx && nx < n;
	}

	int n, m;
	int[][] map;
	int[][] p;
	boolean[][] v;
	int[][] move = { { -1, 0 }, { 0, -1 }, { 0, 1 }, { 1, 0 } };
}