黑白棋游戏 (codevs 2743)题解

【问题描述】

     黑白棋游戏的棋盘由4×4方格阵列构成。棋盘的每一方格中放有1枚棋子,共有8枚白棋子和8枚黑棋子。这16枚棋子的每一种放置方案都构成一个游戏状态。在棋盘上拥有1条公共边的2个方格称为相邻方格。一个方格最多可有4个相邻方格。在玩黑白棋游戏时,每一步可将任何2个相邻方格中棋子互换位置。对于给定的初始游戏状态和目标游戏状态,编程计算从初始游戏状态变化到目标游戏状态的最短着棋序列。

【样例输入】

    1111

    0000

    1110

    0010

    1010

    0101

    1010

    0101

【样例输出】  

    4

    1222

    1424

    3242

    4344

【解题思路】

     看到最少步数,果断广搜。不过状态太多,需要判重。大家可以看到,出题人在数据一栏写了必须用状态压缩,不能用康托展开和hash,他说往东走,咱们偏往西走,就用hash优化。(别想从我嘴里套出我不会状态压缩和康托展开)不过hash函数会很不好找,这里我用的是二进制转十进制的方法存hash,这样的话保证每种状态下只有一个hash函数,就不需要挂链表了,主要的是比较目前状态与目标状态是否相同时会耗费点时间,不过1s还是能过的,然后一个关键的地方就是存储哪两个坐标换了位置,我是用的字符来存的,详见代码。

【代码实现】

  1 type arr=array[1..5,1..5] of char;
  2      rec=record
  3      m:arr;
  4      step:longint;
  5      ans:array[1..100,1..5] of char;
  6 end;
  7 const dx:array[1..4] of longint=(1,-1,0,0);
  8       dy:array[1..4] of longint=(0,0,-1,1);
  9 var start,ans:rec;
 10     f:array[0..200000] of boolean;
 11     spos,epos:arr;
 12     fr,r,i,j:longint;
 13     a:array[1..200000] of rec;
 14 function equal(m:arr):boolean;
 15 var i,j:longint;
 16 begin
 17  for i:=1 to 4 do
 18   for j:=1 to 4 do
 19    if m[i,j]<>epos[i,j] then exit(false);
 20  exit(true);
 21 end;
 22 function hash(m:arr):longint;//二进制转十进制,用位运算,效率高
 23 var res,i,j:longint;
 24 begin
 25  res:=0;
 26  for i:=1 to 4 do
 27   for j:=1 to 4 do
 28    begin
 29     res:=(res shl 1);
 30     res:=res+ord(m[i,j])-ord('0');
 31    end;
 32  exit(res);
 33 end;
 34 procedure bfs;
 35 var t,i,j,k,x,y:longint;
 36     now,next:rec;
 37     temp:char;
 38 begin
 39  fillchar(f,sizeof(f),true);
 40  t:=hash(spos);
 41  f[t]:=false;
 42  fr:=0;r:=1;
 43  while fr<>r do
 44   begin
 45    inc(fr);
 46    now:=a[fr];
 47    if equal(now.m) then
 48     begin
 49      ans:=now;
 50      exit;
 51     end;
 52    for i:=1 to 4 do
 53     for j:=1 to 4 do
 54      for k:=1 to 4 do
 55       begin
 56        next:=now;
 57        inc(next.step);
 58        x:=i+dx[k];
 59        y:=j+dy[k];
 60        if (x>=1)and(x<=4)and(y>=1)and(y<=4) then
 61         begin
 62          temp:=next.m[i,j];
 63          next.m[i,j]:=next.m[x,y];
 64          next.m[x,y]:=temp;
 65          next.ans[next.step,1]:=chr(ord('0')+i);
 66          next.ans[next.step,2]:=chr(ord('0')+j);
 67          next.ans[next.step,3]:=chr(ord('0')+x);
 68          next.ans[next.step,4]:=chr(ord('0')+y);
 69          next.ans[next.step,5]:=#0;//存储哪两个坐标换了位置
 70          if equal(next.m) then
 71           begin
 72            ans:=next;
 73            exit;
 74           end;
 75          t:=hash(next.m);
 76          if f[t] then
 77           begin
 78            f[t]:=false;
 79            inc(r);
 80            a[r]:=next;
 81           end;
 82         end;
 83       end;
 84    end;
 85 end;
 86 begin
 87  for i:=1 to 4 do
 88   begin
 89    for j:=1 to 4 do
 90     read(spos[i,j]);
 91    readln;
 92   end;
 93  for i:=1 to 4 do
 94   begin
 95    for j:=1 to 4 do
 96     read(epos[i,j]);
 97    readln;
 98   end;
 99  for i:=1 to 4 do
100   for j:=1 to 4 do
101    start.m[i,j]:=spos[i,j];
102  start.step:=0;
103  a[1]:=start;
104  bfs;
105  writeln(ans.step);
106  for i:=1 to ans.step do
107   begin
108    for j:=1 to 4 do
109     write(ans.ans[i,j]);
110    writeln;
111   end;
112 end.

 

转载于:https://www.cnblogs.com/PengBoLiuXu/p/4518105.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值