八数码问题的三种算法解答(C#源代码)

 

详细工程文件的下载地址: http://download.csdn.net/source/195320

/*----------------------------------------------------------------
          // Copyright (C) 2007 Fengart
          // 版权所有。 
          // 开发者:Fengart
          // 文件名:FengartAI.cs
          // 文件功能描述:这是一个能够解决八数码问题的高效方法,主要体现在对状态编码上。
 /*----------------------------------------------------------------
    //主页:
http://fengart.9126.com
    //blog: 
http://blog.csdn.net/fengart
    //Emial: fengart@126.com
//----------------------------------------------------------------
*/

using  System;
using  System.Collections.Generic;

namespace  Eight_Num_Fengart
{
    
/// <summary>
    
///  八数码问题的算法
    
/// </summary>

    class FengartAI
    
{
        
代码说明 

        
/// <summary>
        
/// ten[i]代表10的i次方
        
/// </summary>

        private static readonly long[] tens =1101001000100001000001000000100000001000000001000000000 };

        
/// <summary>
        
/// 不是合理的编码
        
/// </summary>

        private const int OutOfCode = -1;

        
/// <summary>
        
/// 标志是否找到目标状态的编码
        
/// </summary>

        public const int WinnerCode = 1;

        
private Direction[][] dirs;

        
private int startBoard;
        
private static int endBoard;
        
private static int[] endBoardArray;

        
private int MaxDepth;

        
private SortedList<long,StateMsg> openList;
        
private Stack<State> openStack;
        
private Queue<State> openQueue;
        
private Dictionary<long,StateMsg> boardtable;

        
private const int maxNodes = 362880//至多搜索的结点数=最大局面状态数量:(9!)=362880;

        
private int nodes;
        
private int same;
        
private float time;
        
private Direction[] result;

        
/// <summary>
        
/// 已经访问的结点数量
        
/// </summary>

        public int Nodes
        
{
            
get return nodes; }
        }


        
/// <summary>
        
/// 重复访问相同结点的数量
        
/// </summary>

        public int Same
        
{
            
get return same; }
        }


        
public float Time
        
{
            
get return time; }
        }


        
/// <summary>
        
/// 最终结果
        
/// </summary>

        public Direction[] Result
        
{
            
get return result; }
        }


        
public FengartAI()
        
{
            dirs 
= new Direction[9][];
            dirs[
0= new Direction[] { Direction.Right, Direction.Down };
            dirs[
1= new Direction[] { Direction.Left, Direction.Right, Direction.Down };
            dirs[
2= new Direction[] { Direction.Left, Direction.Down };
            dirs[
3= new Direction[] { Direction.Up, Direction.Right, Direction.Down };
            dirs[
4= new Direction[] { Direction.Up, Direction.Left, Direction.Right, Direction.Down };
            dirs[
5= new Direction[] { Direction.Up, Direction.Left, Direction.Down };
            dirs[
6= new Direction[] { Direction.Up, Direction.Right };
            dirs[
7= new Direction[] { Direction.Left, Direction.Right, Direction.Up };
            dirs[
8= new Direction[] { Direction.Up, Direction.Left };

        }


        
/// <summary>
        
/// 求与目标位置不同的个数(不计空格,因此返回值0~8)
        
/// </summary>
        
/// <param name="curboard"></param>
        
/// <returns></returns>

        public static int Different(int curboard)
        
{
            
int t_start = curboard;
            
int emp_start = curboard % 10;
            
int ev = 0;
            
//写2个for是为了减少9个if
            for (int i = 9; i > emp_start; i--)
            
{
                t_start 
/= 10;
                
if (t_start % 10 != endBoardArray[i])
                    ev
++;
            }

            
for (int i = emp_start - 1; i >= 1; i--)
            
{
                t_start 
/= 10;
                
if (t_start % 10 != endBoardArray[i])
                    ev
++;
            }

            
return ev;
        }


        
public static int getBoard(long code)
        
{
            
return (int)(code % tens[9]);
        }


        
private static int getEval(long code)
        
{
            
return (int)(code / tens[9]);
        }


        
private static int getEmpIndex(long code)
        
{
            
return (int)(code % 10);
        }


        
private static long combinCode(int board, int eval)
        
{
            
long codehead = eval * tens[9];
            
return codehead + board;
        }


        
/// <summary>
        
/// 改变局面(移动空格)
        
/// </summary>
        
/// <param name="code"></param>
        
/// <param name="dir"></param>

        public static long change(long code, Direction dir)
        
{
            
int newboard;
            
int eval;
            
int num;
            
int t0;
            
long t1;
            
long t2;
            
switch (dir)
            
{
                
case Direction.Left:
                    newboard 
= getBoard(code) - 1;
                    
if (newboard == endBoard)
                        
return WinnerCode;
                    eval 
= Different(newboard);
                    
return combinCode(newboard, eval);
                
case Direction.Right:
                    newboard 
= getBoard(code) + 1;
                    
if (newboard == endBoard)
                        
return WinnerCode;
                    eval 
= Different(newboard);
                    
return combinCode(newboard, eval);
                
case Direction.Up:
                    num 
= getBoard(code);
                    t0 
= 9 - num % 10 + 1;
                    t1 
= num / tens[t0];
                    t2 
= t1 % 1000;
                    t1 
= t1 - t2 + (t2 % 100* 10 + t2 / 100;
                    t1 
*= tens[t0];
                    newboard 
= (int)(t1 + ((num % tens[t0]) - 3));
                    
if (newboard == endBoard)
                        
return WinnerCode;
                    eval 
= Different(newboard);
                    
return combinCode(newboard, eval);
                
case Direction.Down:
                    num 
= getBoard(code);
                    t0 
= 9 - num % 10 + 1 - 3;//跟Up不同的地方
                    t1 = num / tens[t0];
                    t2 
= t1 % 1000;
                    t1 
= t1 - t2 + (t2 % 10* 100 + t2 / 10;//跟Up不同的地方
                    t1 *= tens[t0];
                    newboard 
= (int)(t1 + ((num % tens[t0]) + 3));//跟Up不同的地方
                    if (newboard == endBoard)
                        
return WinnerCode;
                    eval 
= Different(newboard);
                    
return combinCode(newboard, eval);
            }

            
return OutOfCode;
        }


        
/// <summary>
        
/// 恢复上一步的局面
        
/// </summary>
        
/// <param name="code"></param>
        
/// <param name="dir"></param>

        public long unchange(long code, Direction dir)
        
{
            
return change(code, (Direction)(5 - dir));
        }


        
/// <summary>
        
/// 当找到目标时,从哈希表里找原来的路径
        
/// </summary>
        
/// <param name="endCode"></param>
        
/// <param name="depth"></param>

        private void setResult(long endCode, Direction curDir, Direction lastDir, int depth)
        
{
            
long lastCode = endCode;
            result 
= new Direction[depth];
            result[depth 
- 1= curDir;
            
for (int i = depth - 2; i >= 0; i--)
            
{
                
if (boardtable.ContainsKey(lastCode))
                
{
                    result[i] 
= boardtable[lastCode].Dir;
                    lastCode 
= unchange(lastCode, result[i]);
                }

                
else
                    
return;
            }

        }


        
//本算法的核心部分

        
带Open表和HashTable的最好优先搜索(每次扩展Open表后都对Open表排序)

        
带Open表和HashTable的深度优先搜索(排序后才插入Open表)

        
带Open表和HashTable的广度优先搜索(排序后才插入Open表)

        
/// <summary>
        
/// 把一维数组的局面编码成一个整数的表示形式
        
/// </summary>
        
/// <param name="genBoard"></param>
        
/// <returns></returns>

        public int ToIntBoard(int[] genBoard)
        
{
            
int board = 0;
            
int emp = 0;
            
for (int i = 0; i < genBoard.Length; i++)
            
{
                
if (genBoard[i] != 0)
                    board 
= 10 * board + genBoard[i];
                
else
                    emp 
= i + 1;
            }

            
return 10 * board + emp;
        }


        
/// <summary>
        
/// 判断是否可以从初始状态到达目标状态(计算两个状态的逆序列,奇偶性相同的返回true)
        
/// </summary>
        
/// <param name="start"></param>
        
/// <param name="end"></param>
        
/// <returns></returns>

        private bool ExistAns(int[] start, int[] end)
        
{
            
int sequence_start = 0, sequence_end = 0;
            
for (int i = 0; i < start.Length; i++)
            
{
                
if (start[i] != 0)
                    
for (int j = i + 1; j < start.Length; j++)
                    
{
                        
if (start[j] != 0 && start[j] < start[i])
                            sequence_start
++;
                    }

                
if (end[i] != 0)
                    
for (int j = i + 1; j < start.Length; j++)
                    
{
                        
if (end[j] != 0 && end[j] < end[i])
                            sequence_end
++;
                    }

            }

            
return (sequence_start + sequence_end) % 2 == 0;
        }


        
/// <summary>
        
/// 初始化求解
        
/// </summary>
        
/// <param name="start"></param>
        
/// <param name="end"></param>
        
/// <param name="maxDepth"></param>

        private void InitComp(int[] start, int[] end, int maxDepth)
        
{
            nodes 
= 0;
            same 
= 0;
            MaxDepth 
= maxDepth;
            result 
= null;
            boardtable 
= new Dictionary<long, StateMsg>();
            openList 
= new  SortedList<long,StateMsg>();
            openStack 
= new Stack<State>();
            openQueue 
= new Queue<State>();

            
this.startBoard = ToIntBoard(start);
            endBoard 
= ToIntBoard(end);
            
int t_end = endBoard;
            
int emp_end = endBoard % 10;
            endBoardArray 
= new int[10];
            endBoardArray[
0= emp_end;
            endBoardArray[emp_end] 
= 0;
            
for (int i = 9; i > emp_end; i--)
            
{
                t_end 
/= 10;
                endBoardArray[i] 
= t_end % 10;
            }

            
for (int i = emp_end - 1; i >= 1; i--)
            
{
                t_end 
/= 10;
                endBoardArray[i] 
= t_end % 10;
            }

        }


        
/// <summary>
        
/// 求解8数码问题
        
/// </summary>
        
/// <param name="start"></param>
        
/// <param name="end"></param>

        public Answer Compute(int[] start, int[] end, int maxDepth, int mode)
        
{
            
if (!ExistAns(start, end))
                
return Answer.NotExist;
            InitComp(start, end, maxDepth);
            
if (startBoard == endBoard)
                
return Answer.Exist;
            
long oldtime = System.DateTime.Now.Ticks;
            
int eval = 0;
            
switch (mode)
            
{
                
case 0:
                    eval 
= DepthFirstSearch();
                    
break;
                
case 1:
                    eval 
= BreadthFirstSearch();
                    
break;
                
case 2:
                    eval 
= BestFirstSearch();
                    
break;
                
default:
                    eval 
= BestFirstSearch();
                    
break;
            }

            time 
= (System.DateTime.Now.Ticks - oldtime) / 10000000.0f;
            
if (eval == WinnerCode)
                
return Answer.Exist;
            
return Answer.NotExistInDepth;
        }


    }

}

 
  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值