【9801】黑白棋游戏 - Pascal

题目描述

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

输入输出格式

输入格式:

输入文件共有8行。前四行是初始游戏状态,后四行是目标游戏状态。每行4个数分别表示该行放置的棋子颜色。“0”表示白棋;“1”表示黑棋。

输出格式:

输出文件的第一行是着棋步数n。接下来n行,每行4个数分别表示该步交换棋子的两个相邻方格的位置。例如,abcd表示将棋盘上(a,b)处的棋子与(c,d)处的棋子换位。

注意

本题可能有多种解法,不保证每一种解法均AC


Sample inputSample output
1111
0000
1110
0010
1010
0101
1010
0101
4
1222
1424
3242
4344




解题报告:

  这道题是一道比较典型的搜索类型的题目,难度一般。

  打搜索题比较要注意的是题目类型:需不需要判重(判断是否为重复情况),以及如何判重。而本题显然是必须要经过判重这一步骤,每当黑白两种棋子对调,对调完后的棋面很可能是之前已经出现过的情况,因而需要判重。

  在选择判重方案时,这道题同时有一个比较特殊的地方:每个点只有0和1两种情况,这就很容易联想到二进制,二进制本身每一位也只有0和1两种情况。我这里采用的方法是把一张4×4的棋谱横向展开,把它变成一个16位的二进制数,因为每一个点的0、1不同,其对应的二进制数也不同,同样的把二进制转换成十进制也不同,最后加上boolean型就可以轻松判重了。 

  解决判重方案剩下的无非就是搜索,这里采用BFS(广搜)算法,用结构体(记录类型)记录第i种情况下的棋谱、步数。 

  对了,还有一个剪枝方法(应该是很容易就可以想到):想要交换的两点若颜色相同,不交换,跳到下一步。


program m9801;

type std=array[0..5,0..5] of '0'..'1';
        chong=array[0..65536] of boolean;
        rec=record
           m:std;
           step:longint;
           ans:array[0..200,1..4] of 0..5;
        end;

const dx:array[1..2] of -1..1=(1,0);
      dy:array[1..2] of -1..1=(0,1);

var  i,j,k,g,h,t,zhong:longint;
     s:string;
     f:chong;
     zan:array[0..50000] of rec;
     a,b :std;

function power(a,b:longint):longint;
var i,j:longint;
begin
  j:=1;
  for i:=1 to b do
      j:=j*2;
  exit(j);
end;

procedure print(pp:rec);
var i,j,t:longint;
begin
  writeln(pp.step);
  for i:=1 to pp.step do
  begin
    for j:=1 to 4 do
      write(pp.ans[i,j]);
    writeln;
  end;
end;

function change(newf:std):longint;
var i,j,tmp:longint;
begin
change:=0;
  for i:=1 to 4 do
    for j:=1 to 4 do
      begin
        tmp:=ord(newf[i,j])-ord('0');
        change:=change+trunc(tmp*power(2,4*(4-i)+(4-j)));
      end;
end;

function check(newf:std):boolean;
var i,j:longint;
begin
  for i:=1 to 4 do
    for j:=1 to 4 do
      if newf[i,j] <> b[i,j] then exit(false);
  exit(true);
end;

procedure bfs;
var i,j,t,x,y,tt,tmp,k,head,tail:longint;
    c:char;
    temp:std;
    next:rec;
begin
   head:=0;
   tail:=1;
   zan[1].m:=a;
   zan[1].step:=0;
   f[change(a)]:=true;
   repeat;
     inc(head);
     temp:=zan[head].m;
     tmp:=zan[head].step;
           for i:=1 to 4 do
             for j:=1 to 4 do
               for k:=1 to 2 do
                  begin
                    x:=i+dx[k];
                    y:=j+dy[k];
                    if (x>0) and (x<=4) and (y>0) and (y<=4) and (temp[i,j]<>temp[x,y]) then
                       begin
                          c:=temp[x,y];
                          temp[x,y]:=temp[i,j];
                          temp[i,j]:=c;
                          tt:=change(temp);
                          If not f[tt] then begin
                          inc(tail);
                          zan[tail].m:=temp;
                          zan[tail].step:=tmp+1;
                          zan[tail].ans:=zan[head].ans;
                          zan[tail].ans[tmp+1,1]:=i;
                          zan[tail].ans[tmp+1,2]:=j;
                          zan[tail].ans[tmp+1,3]:=x;
                          zan[tail].ans[tmp+1,4]:=y;
                          if tt = zhong then
                            begin
                              print(zan[tail]);
                              halt;
                            end;
                          F[tt]:=true;
                          End;
                          c:=temp[x,y];
                          temp[x,y]:=temp[i,j];
                          temp[i,j]:=c;
                      end;
                    end;
  until head>tail;
end;

begin
  fillchar(f,sizeof(f),false);
  for i:=1 to 4 do
    begin
      readln(s);
      for j:=1 to 4 do
         a[i,j] :=s[j];
    end;
  for i:=1 to 4 do
     begin
       readln(s);
        for j:=1 to 4 do
          b[i,j]:=s[j];
     end;
  zhong:=change(b);
  bfs;
end.





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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值