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: Time Limit Exceeded)

#include <stdio.h>
#include <list>
#include <iostream>

using namespace std;

#define GU (-100)

list<unsigned long long> LineData[32];
int map[8 + 2][8 + 2];
int n;

int make_line(int x, int y, int now, int goal, unsigned long long flag, int start_id)
{
	if (now == goal){
		LineData[start_id].push_back(flag);
		return (0);
	}
	
	if (map[x][y] <= 0 || now > goal || (flag >> ((y - 1) * 8 + (x - 1))) & 1 == 1){
		return (0);
	}
	
	now += map[x][y];
	int d = (((y - 1) * 8) +  (x - 1));
	
	*(((int *)(&flag)) + (d / 32)) |= 1 << (d % 32);
	
	make_line(x + 1, y, now, goal, flag, start_id);
	make_line(x - 1, y, now, goal, flag, start_id);
	make_line(x, y + 1, now, goal, flag, start_id);
	make_line(x, y - 1, now, goal, flag, start_id);
	
	return (0);
}

bool is_clear(int depth, int start_cnt, unsigned long long flag)
{
	list<unsigned long long>::iterator it;
	
	if (depth == start_cnt){
		int st_cnt;
		st_cnt = 0;
		for (int i = 0; i < 64; i++){
			st_cnt += (*(((int *)(&flag)) + (i / 32)) >> i % 32) & 1;
		}
		return (st_cnt == n * n ? true : false);
	}
	
	for (it = LineData[depth].begin(); it != LineData[depth].end(); it++){
		if (flag ^ *it == flag | *it && is_clear(depth + 1, start_cnt, flag | *it) == true){
			return (true);
		}
	}
	
	return (false);
}

int main(void)
{
	int start_cnt;
	long long start_flag;
	
	while (1){
		for (int i = 0; i < 32; i++){
			LineData[i].clear();
		}
		for (int y = 0; y < 10; y++){
			for (int x = 0; x < 10; x++){
				map[x][y] = GU;
			}
		}
		scanf("%d", &n);
		if (n == 0)break;
		
		for (int y = 1; y <= n; y++){
			for (int x = 1; x <= n; x++){
				scanf("%d", &map[x][y]);
			}
		}
		
		start_cnt = start_flag = 0;
		for (int y = 1; y <= n; y++){
			for (int x = 1; x <= n; x++){
				if (map[x][y] < 0){
					make_line(x + 1, y, 0, -map[x][y], 0, start_cnt);
					make_line(x - 1, y, 0, -map[x][y], 0, start_cnt);
					make_line(x, y + 1, 0, -map[x][y], 0, start_cnt);
					make_line(x, y - 1, 0, -map[x][y], 0, start_cnt);
					int d = ((y - 1) * 8 +  (x - 1));
					*(((int *)(&start_flag)) + (d / 32)) |= 1 << (d % 32);
					start_cnt++;
				}
			}
		}
		
		for (int i = 0; i < start_cnt; i++){
			LineData[i].sort();
			LineData[i].unique();
#if 0
			for (list<unsigned long long>::iterator it = LineData[i].begin(); it != LineData[i].end(); it++){
				int sum = 0;
				for (int i = 0; i < 8; i++){
					for (int j = 0; j < 8; j++){
						printf("%d", (*it >> i * 8 + j) & 1);
						if ((*it >> i * 8 + j) & 1 == 1){
							sum += map[j + 1][i + 1];
						}
					}
					puts("");
				}
				printf("%d\n", sum);
			//	getch();
			}
#endif
		}
		printf("%s\n", is_clear(0, start_cnt, start_flag) == true ? "YES" : "NO");
	}
	
	return (0);
}