Problem:
宇宙人のメッセージ

宇宙人 Mr.X は地球への来星記念として、地球人に向けてのメッセージを残しました。 Mr.X がメッセージを残す場所に選んだのは古代遺跡として有名な"トロンコ遺跡"でした。 ここはいろいろな大きさの碁盤のマス目に、奇抜な石像が無造作に配置されている不思議な場所でした。

Mr.X は、メッセージとして、石像が置かれていない全てのマス目を一度だけ通る、単一の閉曲線を描きました。Mr.X はとても賢く、このような閉曲線を描くことが可能な碁盤であれば必ず閉曲線を描き、メッセージを残しました。しかし、石像の配置によっては、閉曲線を描くことが不可能な碁盤もあり、その場合はメッセージを残しませんでした。 図1の碁盤に描かれている閉曲線は、全ての空いているマス目を一度だけ通っています。Mr.X はこのような閉曲線をメッセージとして残しました。

図1

Mr.X は、図2の碁盤に描かれているような閉曲線は描きませんでした。

図2

後に Mr.X のメッセージは、古代遺跡と見事に調和した宇宙人の美として、地球人に夢とロマンを与える伝説となりました。しかし、長年に渡る風化によってメッセージは消えてしまい、伝説だけが残りました。

碁盤の情報を入力とし、Mr.X がその碁盤上にメッセージを残した場合は Yes と、残さなかった場合は No と出力するプログラムを作成してください。ただし、全てのマスに石像が配置されている場合は、No と出力することとします。

Input

複数のデータセットの並びが入力として与えられます。入力の終わりはゼロふたつの行で示されます。各データセットは以下の形式で与えられます。

W H
c1,1 c1,2 ... c1,W
c2,1 c2,2 ... c2,W

:
cH,1 cH,2 ... cH,W

1 行目に碁盤の横方向に並ぶマス目の数 W, 縦方向に並ぶマス目の数 H (1 ≤ W, H ≤ 7) が与えられる。

続く H 行に碁盤の状態が与えられる。ci,j は碁盤の i 行目の左から j 番目のマス目を表す整数であり、0 のとき何も置かれていないマス目、1 のとき石像が置かれているマス目を表す。

データセットの数は 1000 を超えない。

Output

データセットごとに、Yes または No を１行に出力する。

Sample Input

5 4
0 0 0 0 0
0 1 1 0 0
0 0 1 0 1
1 0 0 0 1
5 4
0 0 0 0 0
0 1 1 0 0
0 0 0 0 1
1 0 0 0 1
0 0

Output for the Sample Input

Yes
No

Solution in JAVA (judge verdict: Accepted)


import java.util.Scanner;

public class Main {

	public static void main(String[] args) {

		new Main().run();
	}

	private void run() {
		Scanner scanner = new Scanner(System.in);
		loop: while (true) {
			w = scanner.nextInt();
			h = scanner.nextInt();
			if ((w | h) == 0)
				break;
			count = 0;
			visited = new boolean[h][w];
			sx = -1;
			sy = -1;
			boolean isworstpatt = (w == 7 && h == 7);
			for (int i = 0; i < h; i++) {
				for (int j = 0; j < w; j++) {
					int now = scanner.nextInt();
					if (now == 0) {
						count++;
						if (sx == -1) {
							sy = i;
							sx = j;
						}
					} else {
						isworstpatt = false;
						visited[i][j] = true;
					}
				}
			}
			if(count%2==1){
				System.out.println("No");
				continue;
			}
			if (isworstpatt) {
				System.out.println("No");
				continue;
			}
			for (int i = 0; i < h; i++) {
				for (int j = 0; j < w; j++) {
					if (visited[i][j])
						continue;
					int count = 0;
					for (int k = 0; k < 4; k++) {
						int x = j + vx[k];
						int y = i + vy[k];
						if (!isOK(x, y))
							continue;
						if (!visited[y][x])
							count++;
					}
					if (count < 2) {
						System.out.println("No");
						continue loop;
					}
				}
			}

			System.out.println(dfs(sx, sy, 0) ? "Yes" : "No");
		}

	}

	private boolean dfs(int x, int y, int deep) {
		if (count - deep < Math.abs(x - sx) + Math.abs(y - sy))
			return false;

		for (int i = 0; i < 4; i++) {
			int nx = x + vx[i];
			int ny = y + vy[i];
			if (!isOK(nx, ny))
				continue;
			if (ny == sy && nx == sx && deep + 1 == count)
				return true;
			if (visited[ny][nx])
				continue;
			boolean res = check(nx, ny);
			if (!res)
				continue;
			visited[ny][nx] = true;
			if (dfs(nx, ny, deep + 1))
				return true;
			visited[ny][nx] = false;
		}
		return false;

	}

	private boolean check(int x, int y) {
		loop: for (int i = 4; i < vx.length; i++) {
			int nx = x + vx[i];
			int ny = y + vy[i];
			if (!isOK(nx, ny))
				continue;
			if (nx == sx && ny == sy)
				continue;
			if (visited[ny][nx])
				continue;
			int count = 0;
			for (int j = 0; j < 4; j++) {
				int nnx = nx + vx[j];
				int nny = ny + vy[j];
				if (!isOK(nnx, nny))
					continue;
				if (visited[nny][nnx])
					continue;
				count++;
				if (count == 2)
					continue loop;
			}
			return false;
		}
		return true;
	}

	private boolean isOK(int x, int y) {
		if (0 <= x && x < w && 0 <= y && y < h)
			return true;
		return false;
	}

	boolean[][] visited;
	boolean ans;
	int count, w, h, sx, sy;
	int[] vx = { 0, 1, 0, -1, 1, 1, -1, -1 };
	int[] vy = { -1, 0, 1, 0, -1, 1, 1, -1 };
}