深度優先搜索的過河問題應用

問題:數組

一個警察和一個犯人,一個爸爸一個媽媽,兩個兒子兩個女兒,他們要過河,有一艘船一次只能坐兩我的,爸爸不在媽媽打兒子,媽媽不在爸爸打女兒。警察不在。犯人殺人。怎樣才能過河?安全

解決思路梗概:
一、將八我的轉換成八位2進制數,0表示在左岸,1表示在右岸。如警察在右岸就是 10000000,因此經過當前位置狀態與0x80進行&按位與就能得出警察當前是否已過河。
 
二、經過給定的條件,若是警察不在犯人會傷人等條件判斷是否位置狀態安全。只有在安全且以前沒有到達過此位置狀態的狀況下才會到達此位置狀態。
 
三、外層while循環,判斷是否已經都過河了,內層for循環每一個人和三個能開船的人進行位置狀態匹配。兩個數組一個棧,一個數組記錄已經走過的位置狀態,另一個記錄船的位置。棧用來記錄符合條件的位置狀態,如此條路已經入棧了,可是後面發現走不通,則移除棧頂元素,從新循環。由於數組已經記錄了因此走過的狀況,故不會走老路。
若是還走不通,繼續移除棧頂元素,直到走通。 以下圖,A—>D—>A—>C—>A—>B—>F
 
一句話來講就是,我一條一條的路線去遍歷,走着走着走不通了,就退回上一步重新走,由於每走一步我都作了記錄(位置和方向),因此不會走到重複的路線,只要有解確定就能走通。
 
 
代碼實現
 class Program
    {
        static void Main(string[] args)
        {

            List<int> list = crossRiverProblem();

            Console.WriteLine("---------八人從左往右過河的實現------------");
            List<string> processList = resultProcess(list);
            for (int i = 0; i < list.Count; i++)
            {
                string resultByte = result(Convert.ToString(list[i], 2));
                string resultChi = resultChinese(resultByte);
                //Console.WriteLine(resultByte + "---" + resultChi + "---->" + processList[i] + "---" + list[i]);
                Console.WriteLine(resultByte + "---" + resultChi + "---->" + processList[i]);
            }
     
            Console.WriteLine("---------執行結束------------");
            Console.ReadKey();
        }

        #region 結果補齊2進制
        /// <summary>
        ///  結果補齊2進制
        /// </summary>
        /// <param name="content"></param>
        /// <returns></returns>
        public static string result(string content)
        {
            int contentLength = content.Length;
            switch (contentLength)
            {
                case 1:
                    return "0000000" + content;
                case 2:
                    return "000000" + content;
                case 3:
                    return "00000" + content;
                case 4:
                    return "0000" + content;
                case 5:
                    return "000" + content;
                case 6:
                    return "00" + content;
                case 7:
                    return "0" + content;
                case 8:
                    return content;
                default:
                    return content;
            }
        }
        #endregion

        #region 結果轉換成漢字
        /// <summary>
        /// 結果轉換成漢字
        /// </summary>
        /// <param name="result"></param>
        /// <returns></returns>
        public static string resultChinese(string result)
        {
            char[] resultChar = result.ToCharArray();

            StringBuilder strB = new StringBuilder();
            for (int i = 0; i < resultChar.Length; i++)
            {
                if (i == 0)
                {
                    strB.Append(resultChar[i] == '1' ? "" : "");
                }
                if (i == 1)
                {
                    strB.Append(resultChar[i] == '1' ? "" : "");
                }
                if (i == 2)
                {
                    strB.Append(resultChar[i] == '1' ? "" : "");
                }
                if (i == 3)
                {
                    strB.Append(resultChar[i] == '1' ? "" : "");
                }
                if (i == 4)
                {
                    strB.Append(resultChar[i] == '1' ? "" : "");
                }
                if (i == 5)
                {
                    strB.Append(resultChar[i] == '1' ? "" : "");
                }
                if (i == 6)
                {
                    strB.Append(resultChar[i] == '1' ? "" : "");
                }
                if (i == 7)
                {
                    strB.Append(resultChar[i] == '1' ? "" : "");
                }


            }
            return strB.ToString();

        }
        #endregion

        #region 過河過程描述
        /// <summary>
        /// 過河過程
        /// </summary>
        /// <param name="list"></param>
        /// <returns></returns>
        public static List<string> resultProcess(List<int> list)
        {
            List<string> processStr = new List<string>(list.Count());
            bool chuanLocation = false;//船的初始位置 在左邊 就是0 false
            string firstName = "";
            string second = "";
            for (int i = 0; i < list.Count(); i++)
            {
                firstName = "";
                second = "";
                if (i == list.Count()-1)
                {
                    processStr.Add("過河完成");
                }
                else
                {
                    int newlocation = list[i] ^ list[i + 1];

                    if (jingLocation(newlocation))
                    {
                        firstName = "警察";
                    }
                    if (fanLocation(newlocation))
                    {
                        second = "犯人";
                       
                    }
                    if (fuLocation(newlocation))
                    {
                        if (string.IsNullOrWhiteSpace(firstName))
                        {
                            firstName = "父親";
                        }
                        else
                        {
                            second = "父親";
                        }
                        
                    }
                    if (erfLocation(newlocation))
                    {
                        second = "兒子";
                    }
                    if (ersLocation(newlocation))
                    {
                        second = "兒子";
                    }
                    if (muLocation(newlocation))
                    {
                        if (string.IsNullOrWhiteSpace(firstName))
                        {
                            firstName = "母親";
                        }
                        else
                        {
                            second = "母親";
                        }
                    }
                    if (nvfLocation(newlocation))
                    {
                        second = "女兒";
                    }
                    if (nvsLocation(newlocation))
                    {
                        second = "女兒";
                    }

                    if (chuanLocation)
                    {
                        if (string.IsNullOrWhiteSpace(second))
                        {
                            processStr.Add(firstName + "本身從右往左過河");
                        }
                        else
                        {
                            processStr.Add(firstName + "帶着" + second + "從右往左過河");
                        }

                    }
                    else
                    {
                        if (string.IsNullOrWhiteSpace(second))
                        {
                            processStr.Add(firstName + "本身從左往右過河");
                        }
                        else
                        {
                            processStr.Add(firstName + "帶着" + second + "從左往右過河");
                        }
                    }

                    chuanLocation = !chuanLocation;
                }
            }


            return processStr;

        }
        #endregion

        #region 人所在的位置判斷 0表示在左岸,1表示在右岸
        /// <summary>
        /// 
        /// </summary>
        /// <param name="location">當前位置狀態</param>
        /// <returns>false 左岸,true 右岸</returns>

        // &是按位與,0x80表示十六進制數128(二進制爲10000000)---警察
        public static bool jingLocation(int location)
        {
            return (0 != (location & 0x80));
        }
        // 0x40表示十六進制數64(二進制爲01000000)---犯人
        public static bool fanLocation(int location)
        {
            return (0 != (location & 0x40));
        }
        // 0x20表示十六進制數64(二進制爲00100000)---父親
        public static bool fuLocation(int location)
        {
            return (0 != (location & 0x20));
        }
        // 0x10表示十六進制數16(二進制爲00010000)---第一個兒子
        public static bool erfLocation(int location)
        {
            return (0 != (location & 0x10));
        }
        // 0x08表示十六進制數8(二進制爲00001000)---第二個兒子
        public static bool ersLocation(int location)
        {
            return (0 != (location & 0x08));
        }
        // 0x04表示十六進制數4(二進制爲00000100)---母親
        public static bool muLocation(int location)
        {
            return (0 != (location & 0x04));
        }
        // 0x02表示十六進制數2(二進制爲00000010)---第一個女兒
        public static bool nvfLocation(int location)
        {
            return (0 != (location & 0x02));
        }
        // 0x01表示十六進制數1(二進制爲00000001)---第二個女兒
        public static bool nvsLocation(int location)
        {
            return (0 != (location & 0x01));
        }
        #endregion

        #region 判斷是否安全的狀態
        /// <summary>
        /// 判斷是否安全的狀態
        /// </summary>
        /// <param name="location"></param>
        /// <returns></returns>
        public static bool isSafe(int location)
        {
            //犯人傷人:警察和犯人不在同一側 犯人一側有人
            if ((fanLocation(location) != jingLocation(location)) && ((fanLocation(location) == fuLocation(location)) ||
                (fanLocation(location) == erfLocation(location)) || (fanLocation(location) == ersLocation(location)) ||
                (fanLocation(location) == muLocation(location)) || (fanLocation(location) == nvfLocation(location)) ||
                (fanLocation(location) == nvsLocation(location))))
            {
                return false;
            }

            //父親傷女兒:父親和母親不在一側 父親一側有女兒
            if ((fuLocation(location) != muLocation(location)) && ((fuLocation(location) == nvfLocation(location)) ||
               (fuLocation(location) == nvsLocation(location))))
            {
                return false;
            }

            //母親傷兒子:父親和母親不在一側 母親一側有兒子
            if ((muLocation(location) != fuLocation(location)) && ((muLocation(location) == erfLocation(location)) ||
               (muLocation(location) == ersLocation(location))))
            {
                return false;
            }

            // 安全狀態
            return true;
        }
        #endregion

        #region 過河問題處理
        /// <summary>
        /// 過河問題處理
        /// </summary>
        /// <returns></returns>
        public static List<int> crossRiverProblem()
        {
            Stack<int> stack = new Stack<int>();//建立空棧 符合條件就入棧 走不通了就已經入棧的出棧 
            stack.Push(0);

            int[] route = new int[256]; // 用於記錄已考慮的狀態路徑 八我的 每一個人兩種狀況 2的八次方是256
            string[] chuan = new string[256]; //用於記錄已考慮的路徑執行後船的狀態(左岸仍是右岸)-1是路徑未考慮  在左邊=false 右邊=true 

            // 初始化數組route、chuan
            for (int i = 0; i < 256; i++)
            {
                route[i] = -1;
                chuan[i] = "-1";
            }

            route[0] = 0;
            bool chuanLocation = false;//船的初始位置 在左邊 就是0 false

            int n = 0;//用來判斷是否走不通 就是循環一圈之後是否毫無進展
            int location = stack.Peek();//當前執行的位置狀態

            while ((route[255] == -1))
            {
                //循環每一個人 判斷能否載過去 一、二、四、八、1六、3二、6四、128
                for (int movers = 1; movers <= 128; movers <<= 1)
                {
                    n++;

                    #region 若是船的位置 和警察的位置和要過河的人的(movers)位置在一側
                    if (((0 != (location & 0x80)) == chuanLocation) && ((0 != (location & 0x80)) == (0 != (location & movers))))
                    {
                        // 警察載此人過河 計算新狀態,^爲按位異或,相同爲0,不一樣爲1
                        int newlocation = location ^ (0x80 | movers);

                        //過河後判斷狀態是否安全
                        if (isSafe(newlocation))
                        {
                            //新的狀態沒有走過
                            if ((route[newlocation] == -1))
                            {
                                // 新狀態安全且未處理
                                route[newlocation] = location; // 記錄新狀態 防止重複走
                                chuanLocation = !chuanLocation;//改變船的位置
                                chuan[newlocation] = chuanLocation.ToString(); // 記錄新狀態下船的位置
                                n = 0;//能走通 故把n重置爲0
                                stack.Push(newlocation);//新位置狀態入棧
                                location = newlocation;//當前位置狀態改成新位置狀態
                            }
                            //新的狀態有過 可是船的位置不同
                            else if (chuan[newlocation] != "-1" && (chuan[newlocation] != (!chuanLocation).ToString()))
                            {
                                route[newlocation] = location;
                                chuan[newlocation] = (!chuanLocation).ToString();
                                chuanLocation = !chuanLocation;
                                n = 0;
                                stack.Push(newlocation);
                                location = newlocation;
                            }
                        }
                    }
                    #endregion

                    #region 若是船的位置 和父親的位置和要過河的人的位置在一側
                    if (((0 != (location & 0x20)) == chuanLocation) && ((0 != (location & 0x20)) == (0 != (location & movers))))//若是當前農夫不在左(0)
                    {
                        int newlocation = location ^ (0x20 | movers);
                        if (isSafe(newlocation))
                        {
                            if ((route[newlocation] == -1))
                            {
                                route[newlocation] = location;
                                chuan[newlocation] = (!chuanLocation).ToString();
                                chuanLocation = !chuanLocation;
                                n = 0;
                                stack.Push(newlocation);
                                location = newlocation;
                            }
                            else if (chuan[newlocation] != "-1" && (chuan[newlocation] != (!chuanLocation).ToString()))
                            {
                                route[newlocation] = location;
                                chuan[newlocation] = (!chuanLocation).ToString();
                                chuanLocation = !chuanLocation;
                                n = 0;
                                stack.Push(newlocation);
                                location = newlocation;
                            }
                        }
                    }
                    #endregion

                    #region 若是船的位置 和母親的位置和要過河的人的位置在一側
                    if (((0 != (location & 0x04)) == chuanLocation) && ((0 != (location & 0x04)) == (0 != (location & movers))))//若是當前農夫不在左(0)
                    {
                        int newlocation = location ^ (0x04 | movers);
                        if (isSafe(newlocation))
                        {
                            if ((route[newlocation] == -1))
                            {

                                route[newlocation] = location;
                                chuan[newlocation] = (!chuanLocation).ToString();
                                chuanLocation = !chuanLocation;
                                n = 0;
                                stack.Push(newlocation);
                                location = newlocation;
                            }
                            else if (chuan[newlocation] != "-1" && (chuan[newlocation] != (!chuanLocation).ToString()))
                            {

                                route[newlocation] = location;
                                chuan[newlocation] = (!chuanLocation).ToString();
                                chuanLocation = !chuanLocation;
                                n = 0;
                                stack.Push(newlocation);

                                location = newlocation;
                            }
                        }

                    }
                    #endregion

                    #region 判斷是否當前狀態下走不通 若是走不通就把已存的結果出棧 由於已走的路徑已經保存 故從新走不會走老路
                    if (n > 8)
                    {
                        //已存的位置狀態出棧
                        int loca = stack.Pop();
                        //Console.WriteLine("移除" + loca);
                        //獲取棧頂的位置狀態做爲最新的位置狀態
                        location = stack.Peek();
                        n = 0;
                        //改變船的位置
                        chuanLocation = !chuanLocation;
                    }
                    #endregion

                }
            }

            // 取出來棧裏的結果
            List<int> resultList = new List<int>();
            int stackLength = stack.Count;
            for (int i = 0; i < stackLength; i++)
            {
                resultList.Add(stack.Pop());
            }
            resultList.Reverse();
            return resultList;
        }
        #endregion
    }

運行結果ui

 項目下載:http://download.csdn.net/detail/fcydxbd/9884916spa

相關文章
相關標籤/搜索