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 C (judge verdict: Accepted)

// AOJ 1034: Line Puzzle
// 2017.9.29 bal4u@uu

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define N 8
#define N2 66

typedef struct { signed char r, c, s, t; } T;
T start[N2]; int m;

signed char map[N][N]; int n, n2;
int mv[4][2] = {{-1,0},{1,0},{0,1},{0,-1}};

int cmp(T *a, T *b)
{
	if (b->s - a->s) return b->s - a->s;
	if (b->r - a->r) return b->r - a->r;
	return a->c - b->c;
}

void print(signed char a[N][N])
{
	int r, c;

	for (r = 0; r < n; r++) {
		for (c = 0; c < n; c++) printf("%3d ", a[r][c]);
		printf("\n");
	}
	printf("\n");
}

int combi(signed char a[N][N], int m0, int n0)
{
	int i, j, f, r, c, s, t, r2, c2, ss, goal;
	signed char tmp[N][N], mk[N2][2];
	T q[N2]; int top;

	if (m0 >= m && n0 >= n2) return 1;
	q[0].r = start[m0].r, q[0].c = start[m0].c, q[0].s = 0, q[0].t = 0, top = 1;
	goal = start[m0].s;
	while (top > 0) {
		r = q[--top].r, c = q[top].c, s = q[top].s, t = q[top].t;
		mk[t][0] = r, mk[t][1] = c;
		for (i = 0; i < 4; i++) {
			r2 = r + mv[i][0], c2 = c + mv[i][1];
			if (r2 < 0 || r2 >= n || c2 < 0 || c2 >= n || a[r2][c2] <= 0) continue;
			for (f = j = 0; j <= t; j++) {
				if (mk[j][0] == r2 && mk[j][1] == c2) { f = 1; break; }
			}
			if (f) continue;
			ss = s + a[r2][c2];
			if (ss < goal) {
				q[top].r = r2, q[top].c = c2, q[top].s = ss, q[top++].t = t + 1;
			} else if (ss == goal) {
				memcpy(tmp, a, sizeof(tmp));
				for (j = 1; j <= t; j++) tmp[mk[j][0]][mk[j][1]] = 0;
				tmp[r2][c2] = 0;
//print(tmp);
				if (combi(tmp, m0+1, n0+t+2)) return 1;
			}
		}
	}
	return 0;
}

int main()
{
	int r, c, t, s;

	while (scanf("%d", &n) && n > 0) {
		n2 = n*n;
		for (s = m = 0, r = 0; r < n; r++) for (c = 0; c < n; c++) {
			scanf("%d", &t);
			if (t < 0) start[m].r = r, start[m].c = c, start[m++].s = -t;
			map[r][c] = t, s += t;
		}
		qsort(start, m, sizeof(T), cmp);
		puts(s == 0 && combi(map, 0, 0) ? "YES" : "NO");
	}
	return 0;
}