八数码问题之哈希优化

[题目描述]
在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字。棋盘中留有一个空格,空格用0来表示。空格周围的棋子可以移到空格中。要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为123804765),找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变。
[输入]
输入初试状态,一行九个数字,空格用0表示
[输出]
只有一行,该行只有一个数字,表示从初始状态到目标状态需要的最少移动次数(测试数据中无特殊无法到达目标状态数据)
[样例输入]
283104765
[样例输出]
4
[参考程序]

program eight;
const
 goal='123804765';
 vx:array[1..4]of integer=(1,-1,3,-3);
 maxn=1200007;
type
 rec=record
  s:string[9];
  step:longint;
 end;
 re=record
  f:boolean;
  s:string[9];
 end;
var
 opt:array[0..maxn] of rec;
 flag:array[0..maxn] of re;
 i,j,n,m,x,w,k:longint;
 v:boolean;
 st,y:string[9];
function lhash(s:string):int64;  //哈希函数
var
 hash:int64;
begin
 val(s,hash);
 lhash:=hash mod maxn;
end;
procedure judge;   //判断是否达到目标
begin
 if opt[m].s=goal then
  begin
   writeln(opt[m].step);
   halt;
  end;
end;
begin
 readln(st);     //读入初始值
 opt[1].s:=st;  //opt[i]表示队列   opt[i].s 是每一步的字符串状态
 opt[1].step:=0;  //opt[i].step表示步数  
 x:=lhash(st);    //lhash是定义的哈希函数   
 flag[x].f:=true; //flag[i]是哈希表  flag[i].f是i位置是否有值 
 flag[x].s:=st;   //flag[i].s是i位置的字符
 i:=1; j:=1; //i对头 j队尾
 while i<=j do   //保证队列不空
  begin
   w:=pos('0',opt[i].s);    //找到0的位置来拓展
   for k:= 1 to 4 do        //有4种移动方法
    if ((w mod 3=1)and(k<>2)or((w mod 3=0))and(k<>1))or(w mod 3=2) then  //w mod 3=1时0在最左边,不能往左移(k<>2);
                                                                         //w mod 3=0时0在最右边,不能往右移(k<>1);
     if (w+vx[k]>0)and(w+vx[k]<=9) then  //保证加上增值后还在范围内  也就是说0要跟范围内的某个数交换
      begin  //条件满足后开始拓展
       y:=opt[i].s; //把要拓展的那串字符给y
       y[w]:=y[w+vx[k]];
       y[w+vx[k]]:='0';  //这两步是把两个位置的值交换
       x:=lhash(y);    //x是在哈希表上的位置
       v:=false;    //v用来判断是否之前已拓展过这个点 即是否与之前重复 v=false即没有重复  v=true即重复了
       while (x<maxn)and(flag[x].f)do  //flag[x].f=true表明这个位置上已有别的数 要在范围内另找一个位置 x是最终找到的位置
        begin
         if flag[x].s=y then  //如果发现该状态之前已存在,就不入队(v:=true)
          begin
           v:=true;
           break;
          end;
         inc(x);
        end;
       if not v then  //如果该状态还没有拓展过就入队
        begin
         inc(j);  //队尾+1
         m:= j mod maxn;   //看起来这步没用 因为不会有如此多部
         opt[m].s:=y;    
         opt[m].step:=opt[i].step+1;  //给队尾赋上值
         flag[x].f:=true;       
         flag[x].s:=y;       //在x位上修改哈希表
         judge;  //判断是否到达目标节点
        end;
      end;
      inc(i);  //拓展完一个状态 队头+1
  end;
end.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值