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 C# (judge verdict: Time Limit Exceeded)

using System;
using System.Collections.Generic;
using System.Linq;

class Program
{
    struct PointDef
    {
        internal int X;
        internal int Y;
    }

    static string InputPattern = "Input2";

    static List<string> GetInputStrList()
    {
        var WillReturn = new List<string>();

        if (InputPattern == "Input1") {
            WillReturn.Add("5 4");
            WillReturn.Add("0 0 0 0 0");
            WillReturn.Add("0 0 1 1 0");
            WillReturn.Add("0 0 1 1 0");
            WillReturn.Add("0 0 0 0 0");
            WillReturn.Add("5 4");
            WillReturn.Add("0 0 0 0 0");
            WillReturn.Add("0 1 1 0 0");
            WillReturn.Add("0 0 1 0 1");
            WillReturn.Add("1 0 0 0 1");
            //WillReturn.Add("5 4");
            //WillReturn.Add("0 0 0 0 0");
            //WillReturn.Add("0 1 1 0 0");
            //WillReturn.Add("0 0 0 0 1");
            //WillReturn.Add("1 0 0 0 1");
            //WillReturn.Add("7 7");
            //WillReturn.Add("0 0 0 0 0 0 0");
            //WillReturn.Add("0 0 0 1 1 1 0");
            //WillReturn.Add("0 0 0 0 0 0 0");
            //WillReturn.Add("0 0 0 0 0 0 0");
            //WillReturn.Add("0 1 0 1 0 1 0");
            //WillReturn.Add("0 0 0 1 0 0 0");
            //WillReturn.Add("0 0 0 0 0 0 0");
            WillReturn.Add("0 0");
            //Yes
            //No
        }
        else {
            string wkStr;
            while ((wkStr = Console.ReadLine()) != null) WillReturn.Add(wkStr);
        }
        return WillReturn;
    }

    static int UB_X;
    static int UB_Y;

    //各空白の4近傍の空白の配列
    struct Space4KinbouInfoDef
    {
        internal PointDef Point;
        internal PointDef[] RinsetuPointArr;
    }
    static Space4KinbouInfoDef[] Space4KinbouInfoArr;

    static void Main()
    {
        List<string> InputStrList = GetInputStrList();
        InputStrList.RemoveAt(InputStrList.Count - 1);

        var InputByteArrList = new List<byte[]>();
        foreach (string EachStr in InputStrList) {
            byte[] WillAdd = EachStr.Split(' ').Select(X => byte.Parse(X)).ToArray();
            InputByteArrList.Add(WillAdd);
        }

        //碁盤の2次元配列のListを作成 
        List<bool[,]> BanArrList = CreateBanArrList(InputByteArrList);

        foreach (bool[,] EachBan in BanArrList) {
            UB_X = EachBan.GetUpperBound(0);
            UB_Y = EachBan.GetUpperBound(1);

            //遺跡情報を表示
            //PrintBan(EachBan);

            //閉曲線を描けるか判定
            Console.WriteLine(CanHeikyokusen(EachBan));
        }
    }

    //碁盤の2次元配列のListを作成 
    static List<bool[,]> CreateBanArrList(List<byte[]> pInputByteArrList)
    {
        var BanArrList = new List<bool[,]>();
        var wkLineBoolList = new List<bool[]>();

        int RestHeight = 0;
        foreach (byte[] EachByteArr in pInputByteArrList) {
            if (RestHeight == 0) {
                RestHeight = EachByteArr[1];
                continue;
            }

            wkLineBoolList.Add(Array.ConvertAll<byte, bool>(EachByteArr, X => X == 1));

            if (--RestHeight == 0) {
                bool[,] wkArr = new bool[wkLineBoolList[0].Length,
                                         wkLineBoolList.Count];
                for (int Y = 0; Y <= wkLineBoolList.Count - 1; Y++) {
                    for (int X = 0; X <= wkLineBoolList[Y].GetUpperBound(0); X++) {
                        wkArr[X, Y] = wkLineBoolList[Y][X];
                    }
                }
                BanArrList.Add(wkArr);
                wkLineBoolList.Clear();
            }
        }
        return BanArrList;
    }

    //閉曲線を描くことが可能な遺跡かを返す 
    static bool CanHeikyokusen(bool[,] pBanArr)
    {
        //石像のないマスの数 
        int NonSekizouMasuCnt = pBanArr.Cast<bool>().Count(X => X == false);
        if (NonSekizouMasuCnt == 0) return false;
        if (NonSekizouMasuCnt == 1) return true;

        //石像のないマスの数が3以上で奇数なら、
        //マンハッタン距離が0に戻る移動ができないのでfalse
        if (NonSekizouMasuCnt % 2 == 1) return false;

        //UnionFindで石像のないマスが全て連結してるかをチェック
        if (IsAllRenketu(NonSekizouMasuCnt, pBanArr) == false) return false;

        //各空白の4近傍の空白の情報を収集
        Space4KinbouInfoArr = DeriveSpace4KinbouInfo(pBanArr);

        //DFSで解の有無をチェック
        return HasAnswer(NonSekizouMasuCnt, pBanArr);
    }

    //各空白の4近傍の空白の情報を収集
    static Space4KinbouInfoDef[] DeriveSpace4KinbouInfo(bool[,] pBanArr)
    {
        var WillReturn = new List<Space4KinbouInfoDef>();
        for (int LoopX = 0; LoopX <= UB_X; LoopX++) {
            for (int LoopY = 0; LoopY <= UB_Y; LoopY++) {
                //石像なら対象外
                if (pBanArr[LoopX, LoopY]) continue;

                Space4KinbouInfoDef WillAdd;
                WillAdd.Point = new PointDef() { X = LoopX, Y = LoopY };
                WillAdd.RinsetuPointArr = DeriveSpace4KinbouArr(pBanArr, LoopX, LoopY);
                WillReturn.Add(WillAdd);
            }
        }

        return WillReturn.ToArray();
    }

    //4近傍の空白の配列を求める
    static PointDef[] DeriveSpace4KinbouArr(bool[,] pBanArr, int pBaseX, int pBaseY)
    {
        var WillReturn = new List<PointDef>();

        Action<int, int> wkAct = (pKinbouX, pKinbouY) =>
        {
            if (pKinbouX < 0 || UB_X < pKinbouX) return;
            if (pKinbouY < 0 || UB_Y < pKinbouY) return;
            //石像なら対象外
            if (pBanArr[pKinbouX, pKinbouY]) return;
            WillReturn.Add(new PointDef() { X = pKinbouX, Y = pKinbouY });
        };

        wkAct(pBaseX, pBaseY - 1);
        wkAct(pBaseX, pBaseY + 1);
        wkAct(pBaseX - 1, pBaseY);
        wkAct(pBaseX + 1, pBaseY);
        return WillReturn.ToArray();
    }

    struct JyoutaiDef_UF
    {
        internal int CurrX;
        internal int CurrY;
    }

    //UnionFindで石像のないマスが全て連結してるかをチェック
    static bool IsAllRenketu(int pNonSekizouMasuCnt, bool[,] pBanArr)
    {
        //石像のないマスから探索開始 
        PointDef NonSekizouZahyou = DeriveNonSekizouZahyou(pBanArr);
        int StaX = NonSekizouZahyou.X;
        int StaY = NonSekizouZahyou.Y;

        var stk = new Stack<JyoutaiDef_UF>();
        JyoutaiDef_UF WillPush;
        WillPush.CurrX = StaX;
        WillPush.CurrY = StaY;
        stk.Push(WillPush);

        var VisitedList = new List<PointDef>();
        VisitedList.Add(NonSekizouZahyou);

        while (stk.Count > 0) {
            JyoutaiDef_UF Popped = stk.Pop();

            //Push処理 
            Action<int, int> PushSyori = (pNewX, pNewY) =>
            {
                if (pNewX < 0 || UB_X < pNewX) return;
                if (pNewY < 0 || UB_Y < pNewY) return;

                //石像なら訪問不可 
                if (pBanArr[pNewX, pNewY]) return;

                //再訪不可 
                PointDef wkPoint = new PointDef() { X = pNewX, Y = pNewY };
                if (VisitedList.Exists(A => A.X == wkPoint.X && A.Y == wkPoint.Y))
                    return;
                VisitedList.Add(wkPoint);

                WillPush.CurrX = pNewX;
                WillPush.CurrY = pNewY;
                stk.Push(WillPush);
            };
            PushSyori(Popped.CurrX, Popped.CurrY - 1);
            PushSyori(Popped.CurrX, Popped.CurrY + 1);
            PushSyori(Popped.CurrX - 1, Popped.CurrY);
            PushSyori(Popped.CurrX + 1, Popped.CurrY);
        }
        return pNonSekizouMasuCnt == VisitedList.Count;
    }

    //石像のないマスの座標を返す
    static PointDef DeriveNonSekizouZahyou(bool[,] pBanArr)
    {
        for (int LoopX = 0; LoopX <= UB_X; LoopX++) {
            for (int LoopY = 0; LoopY <= UB_Y; LoopY++) {
                if (pBanArr[LoopX, LoopY] == false) {
                    return new PointDef() { X = LoopX, Y = LoopY };
                }
            }
        }
        return new PointDef() { X = -1, Y = -1 };
    }

    struct JyoutaiDef_DFS
    {
        internal int CurrX;
        internal int CurrY;
        internal bool[,] BanArr;
        //internal string Path;
        internal int VisitedCnt;
    }

    //DFSで解の有無をチェック
    static bool HasAnswer(int pNonSekizouMasuCnt, bool[,] pBanArr)
    {
        //石像のないマスから探索開始 
        PointDef NonSekizouZahyou = DeriveNonSekizouZahyou(pBanArr);
        int StaX = NonSekizouZahyou.X;
        int StaY = NonSekizouZahyou.Y;

        var stk = new Stack<JyoutaiDef_DFS>();
        JyoutaiDef_DFS WillPush;
        WillPush.CurrX = StaX;
        WillPush.CurrY = StaY;
        WillPush.BanArr = (bool[,])pBanArr.Clone();
        WillPush.BanArr[StaX, StaY] = true;
        //WillPush.Path = string.Format("({0},{1})", StaX, StaY);
        WillPush.VisitedCnt = 1;
        stk.Push(WillPush);

        PointDef[] Sta4KinbouArr = Array.Find(Space4KinbouInfoArr, A => A.Point.X == StaX
                                                                     && A.Point.Y == StaY).RinsetuPointArr;

        while (stk.Count > 0) {
            JyoutaiDef_DFS Popped = stk.Pop();

            //クリア判定
            if (Popped.VisitedCnt == pNonSekizouMasuCnt) {
                //探索開始座標とのマンハッタン距離
                //if (DeriveKyori(StaX, StaY, Popped.CurrX, Popped.CurrY) > 1) continue;
                //Console.WriteLine("解は{0}", Popped.Path);
                return true;
            }

            //開始点の4近傍に到達不能なら枝切り
            if (Array.TrueForAll(Sta4KinbouArr, A => Popped.BanArr[A.X, A.Y]) ) {
                //continue;
            }

            //Push処理 
            Action<int, int> PushSyori = (pNewX, pNewY) =>
            {
                //最初は1方向のみ遷移可とする
                if (Popped.VisitedCnt == 1 && stk.Count > 0) {
                    return;
                }

                if (pNewX < 0 || UB_X < pNewX) return;
                if (pNewY < 0 || UB_Y < pNewY) return;

                //石像または訪問済なら不可
                if (Popped.BanArr[pNewX, pNewY]) return;

                WillPush.CurrX = pNewX;
                WillPush.CurrY = pNewY;
                WillPush.BanArr = (bool[,])Popped.BanArr.Clone();
                WillPush.BanArr[pNewX, pNewY] = true;
                //WillPush.Path = Popped.Path + string.Format("({0},{1})", pNewX, pNewY);
                WillPush.VisitedCnt = Popped.VisitedCnt + 1;

                if (HasHeiro(WillPush.BanArr, pNewX, pNewY, StaX, StaY)) return;

                stk.Push(WillPush);
            };
            PushSyori(Popped.CurrX, Popped.CurrY - 1);
            PushSyori(Popped.CurrX, Popped.CurrY + 1);
            PushSyori(Popped.CurrX - 1, Popped.CurrY);
            PushSyori(Popped.CurrX + 1, Popped.CurrY);
        }
        return false;
    }

    //座標間のマンハッタン距離を返す
    static int DeriveKyori(int pX1, int pY1, int pX2, int pY2)
    {
        return Math.Abs(pX1 - pX2) + Math.Abs(pY1 - pY2);
    }

    //閉路があるかを返す
    static bool HasHeiro(bool[,] pBanArr, int pCurrX, int pCurrY, int pStaX, int pStaY)
    {
        foreach (Space4KinbouInfoDef EachSpace4KinbouInfo in Space4KinbouInfoArr) {
            PointDef CurrPoint = EachSpace4KinbouInfo.Point;

            //通過マスならチェック対象外
            if (pBanArr[CurrPoint.X, CurrPoint.Y]) continue;

            //カレント座標と隣接してたらチェック対象外
            if (DeriveKyori(pCurrX, pCurrY, CurrPoint.X, CurrPoint.Y) == 1) continue;

            //開始座標と隣接してたらチェック対象外
            if (DeriveKyori(pStaX, pStaY, CurrPoint.X, CurrPoint.Y) == 1) continue;

            //隣接している空白の数
            PointDef[] wkArr = EachSpace4KinbouInfo.RinsetuPointArr;
            int SpaceCnt = wkArr.Count(A => pBanArr[A.X, A.Y] == false);
            if (SpaceCnt <= 1) return true;
        }
        return false;
    }

    //盤面を表示
    static void PrintBan(bool[,] pBanArr)
    {
        var sb = new System.Text.StringBuilder();
        for (int Y = 0; Y <= UB_Y; Y++) {
            for (int X = 0; X <= UB_X; X++) {
                sb.Append(pBanArr[X, Y] ? '1' : '0');
            }
            sb.AppendLine();
        }
        Console.WriteLine(sb.ToString());
    }
}