广度优先搜索解决九宫问题

这是布置的 AI 作业,今天有同学用奇怪的“旋转法”做了出来,虽然结果应该不是最优解,不过其思维方式还是很新颖的。课本上有广度优先的介绍,广先的好处是,如果有解,必定能够求出最优解!所以先尝试了一下广先算法,算搞定了,下星期可以交差了。

主要思想:
1、判断两个序列的逆序数的奇偶性是否相同,不同肯定无解,相同就有解。
2、用一个 Queue 存储需要扩展的节点,各用一个 SortList (或者数组、ArrayList、Hasttable等)存储 ClosedList、父节点表(FatherList)、每个状态(节点)对应序列。
3、Queue 开始只有state1,然后出队,进入ClosedList,判断是否可扩展,扩展后的子节点不能与辈份大的节点(父亲、父亲的父亲...)重复。子节点放入 Queue 。
4、只要 Queue 不空,就做循环来找,直到找到一个子节点的序列与 state1 相等,找到后,根据父节点表找到最短路径即可。

C#代码(代码很乱 -__-):
using System;
using System.Text;
using System.Collections;

namespace BlockSimple
{
    
class App
    {

        
enum MovieDirection
        {
            None,
            Up,
            Left,
            Right,
            Down
        }

        
static void Main(string[] args)
        {

            Start:
            
int[,] A=new int[3,3]{{2,8,3},{1,0,4},{7,6,5}};//{{2,8,3},{1,6,4},{7,0,5}}
            int[,] B=new int[3,3]{{1,2,3},{8,0,4},{7,6,5}};//{{1,2,3},{8,0,4},{7,6,5}}
            string stringA=string.Empty;
            
string stringB=string.Empty;
            
int Anxs=0;
            
int Bnxs=0;

            Console.WriteLine(
"Input A:(a1=283104765,a2=283164705)");
            stringA
=Console.ReadLine();
            
if (stringA=="a1")
            {
                stringA
="283104765";
            }
            
if (stringA=="a2")
            {
                stringA
="283164705";
            }

            Console.WriteLine(
"Input B:(b=123804765)");
            stringB
=Console.ReadLine();
            
if (stringB=="b")
            {
                stringB
="123804765";
            }

            
if (stringA.Length!=9 || stringB.Length!=9)
            {
                Console.WriteLine(
"Error! Do it again");
                
goto Start;
            }

            A
=ConvertToAry(stringA);
            B
=ConvertToAry(stringB);

            Console.WriteLine(
"A");
            PrintArray(A);
            Console.WriteLine(
"B");
            PrintArray(B);

            
//逆序数
            Anxs=GetNiXuShu(A);
            Bnxs
=GetNiXuShu(B);
            Console.WriteLine(
"------");
            
            Console.WriteLine(
"A 的逆序数 = "+Anxs.ToString());
            Console.WriteLine(
"B 的逆序数 = "+Bnxs.ToString());
            
if (System.Math.Abs(Anxs-Bnxs) % 2 !=0)
            {
                Console.WriteLine(
"逆序数的奇偶性不同,无解!\r\n");
                
goto Start;
            }
            
else
            {
                Console.WriteLine(
"OK,Continue");
            }
            Console.WriteLine(
"------");
            Console.WriteLine(
"广度优先搜索\r\n------");

            
//广度优先
            
//System.Collections.SortedList OpenList=new SortedList();
            System.Collections.Queue OpenQueue=new Queue();//作为Open表 (int)
            System.Collections.SortedList ClosedList=new SortedList();//作为Closed表 (int,int)
            System.Collections.Hashtable FatherList=new Hashtable();//存储父节点 (int,int)
            System.Collections.Hashtable StateList=new Hashtable();//key=状态代码,value=状态序列 (int,string)


            
//初始化
            int StateCount=1;//状态计数
            
//OpenList.Add(StateCount,0);
            StateList.Add(1,ConvertToString(A));
            OpenQueue.Enqueue(
1);
            FatherList.Add(
1,0);//第一个节点的父亲为0
            int LastStateCount=0;//最后一个状态计数,根据此来通过找出父亲节点,推出最短路径
            bool IsFind=false;

            Console.WriteLine(
"state1:"+StateList[1]+"\tFather:Null");

            
while (OpenQueue.Count>0 && IsFind==false)
            {
                
//OpenList --> ClosedList
                int CurStateCount=(int)OpenQueue.Dequeue();
                ClosedList.Add(CurStateCount,(
int)FatherList[CurStateCount]);//ClosedList好像没有必要加入 父亲节点

                
                
if ((string)StateList[CurStateCount]==stringB)
                {
                    LastStateCount
=CurStateCount;
                    
break;
                }
                
else
                {
                    
//是否可扩展?扩展后将子节点放入OpenList的尾部
                    
//扩展,找到元素0的位置,查看0是否可以上下左右移动,移动后的结果作为子节点(不能与起父节点的序列相同)
                    string CurA=(string)StateList[CurStateCount];

                    MovieDirection[] MD
=new MovieDirection[]{MovieDirection.Left,MovieDirection.Up,MovieDirection.Right,MovieDirection.Down};
                
                    
for (int i=0;i<4;i++)
                    {
                        
if (IsFind)
                        {
                            
break;
                        }
                        
string newMovie=TryMovie(CurA,MD[i]);
                        
//Console.WriteLine(CurA+"-->"+CurStateCount.ToString()+(string)StateList[CurStateCount]);
                        if (newMovie!="")
                        {
                            
//并且不能=父亲、父亲的父亲
                            bool IsEqueFather=false;
                            
int father=CurStateCount;
                            
while (father!=0)
                            {
                                
if (newMovie==(string)StateList[father])
                                {
                                    IsEqueFather
=true;
                                }
                                father
=Convert.ToInt32(FatherList[father]);
                            }

                            
if (IsEqueFather==false)
                            {
                                
//加入到OpenQueue里面
                                StateCount++;
                                OpenQueue.Enqueue((
object)StateCount);
                                FatherList.Add(StateCount,CurStateCount);
                                StateList.Add(StateCount,newMovie);
                                Console.WriteLine(
"state"+StateCount.ToString()+":"+newMovie+"\tFather:"+FatherList[StateCount].ToString()+"");
                                System.Threading.Thread.Sleep(
10);
                                
//判断
                                
//Console.WriteLine((string)StateList[StateCount]+"=?"+stringB);
                                if ((string)StateList[StateCount]==stringB)
                                {
                                    LastStateCount
=StateCount;
                                    IsFind
=true;
                                }
                            }

                        }
                    }

                }
            }

            Console.WriteLine(
"------\r\nFind!state"+LastStateCount.ToString()+"=B\r\n");

            
//找到路径
            int f=LastStateCount;
            
string Path=string.Empty;
            ArrayList p
=new ArrayList();
            
while (f!=0)
            {
                Path
=f.ToString()+"->"+Path;
                p.Add(f);
                f
=Convert.ToInt32(FatherList[f]);
            }

            Console.WriteLine(
"解的路径为: "+Path.Substring(0,Path.Length-2));
            p.Reverse();
            
for (int i=0;i<p.Count;i++)
            {
                
                Console.WriteLine(
"state"+p[i].ToString()+":"+StateList[p[i]]);
                PrintArray(ConvertToAry((
string)StateList[p[i]]));
            }



            Console.WriteLine(
"\r\n----------------------------\r\nTest Again?Input Y");
            
string Test=string.Empty;
            Test
=Console.ReadLine();
            
if (Test.ToLower()=="y")
            {
                
goto Start;
            }
        }

        
//打印矩阵
        private static void PrintArray(int[,] X)
        {
            
for (int i=0;i<3;i++)
            {
                
for (int j=0;j<3;j++)
                {
                    Console.Write(X[i,j].ToString()
+",");
                }
                Console.Write(
"\r\n");
            }
        }
        
//移动0,如果可移,返回移动后的序列,若不可以,返回空
        private static string TryMovie(string XuLie,MovieDirection D)
        {
            
int[,] X=new int[3,3];
            X
=ConvertToAry(XuLie);
            
//参数不应该是数组,因为数组是引用变量
            
//找到0的位置
            int iZero=-1;
            
int jZero=-1;
            
for (int i=0;i<3;i++)
            {
                
for (int j=0;j<3;j++)
                {
                    
if (X[i,j]==0)
                    {
                        iZero
=i;
                        jZero
=j;
                    }
                }
            }


            
if (D==MovieDirection.Left)
            {
                
if (jZero>0)
                {
                    X[iZero,jZero]
=X[iZero,jZero-1];
                    X[iZero,jZero
-1]=0;
                    
return ConvertToString(X);
                }
            }
            
if (D==MovieDirection.Up)
            {
                
if (iZero>0)
                {
                    X[iZero,jZero]
=X[iZero-1,jZero];
                    X[iZero
-1,jZero]=0;
                    
return ConvertToString(X);
                }
            }
            
if (D==MovieDirection.Right)
            {
                
if (jZero<2)
                {
                    X[iZero,jZero]
=X[iZero,jZero+1];
                    X[iZero,jZero
+1]=0;
                    
return ConvertToString(X);
                }
            }
            
if (D==MovieDirection.Down)
            {
                
if (iZero<2)
                {
                    X[iZero,jZero]
=X[iZero+1,jZero];
                    X[iZero
+1,jZero]=0;
                    
return ConvertToString(X);
                }
            }
            
return "";
        }
        
//数组转化成为序列
        private static string ConvertToString(int[,] X)
        {
            
string rtn=string.Empty;
            
for (int i=0;i<3;i++)
            {
                
for (int j=0;j<3;j++)
                {
                    rtn
+=X[i,j].ToString();
                }
            }
            
return rtn;
        }
        
//序列转化称数组
        private static int[,] ConvertToAry(string str)
        {
            
int[,] X=new int[3,3];
            X[
0,0]=Convert.ToInt32(str.Substring(0,1));
            X[
0,1]=Convert.ToInt32(str.Substring(1,1));
            X[
0,2]=Convert.ToInt32(str.Substring(2,1));
            X[
1,0]=Convert.ToInt32(str.Substring(3,1));
            X[
1,1]=Convert.ToInt32(str.Substring(4,1));
            X[
1,2]=Convert.ToInt32(str.Substring(5,1));
            X[
2,0]=Convert.ToInt32(str.Substring(6,1));
            X[
2,1]=Convert.ToInt32(str.Substring(7,1));
            X[
2,2]=Convert.ToInt32(str.Substring(8,1));
            
return X;
        }
        
//计算逆序数,忽略0
        private static int GetNiXuShu(int[,] X)
        {
            
int m=0;
            
int n=0;
            
int[] C=new int[9];

            
for (int i=0;i<3;i++)
            {
                
for (int j=0;j<3;j++)
                {
                    C[n]
=X[i,j];
                    n
++;
                }
            }

            
for (int i=0;i<9;i++)
            {
                
for (int j=i+1;j<9;j++)
                {
                    
if (C[j]!=0 && C[j]<C[i])
                    {
                        m
++;
                    }
                }
            }
            
return m;
        }

    }
}

运行结果:
posted @ 2007-12-04 02:07 卡卡 ^ cacard 阅读(259) 评论(2)  编辑 收藏 所属分类: 算法

  回复  引用    
#1楼 2007-12-06 13:10 | sssssss [未注册用户]
25 宫,81宫 怎么搞,不是要搞很久才算得出来 ,
你听说过斜着走没有
  回复  引用  查看    
#2楼 [楼主]2007-12-07 17:49 | 卡卡 ^ cacard      
道理应该是一样的啊,广度优先或者带深度控制的深度优先以及A*算法,还有其它算法,有待Research!
斜着走?! Cool!

标题  
姓名  
主页
Email (博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
该文被作者在 2007-12-04 02:18 编辑过


相关链接:
 
This is footer