博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

聪明的打字员

Posted on 2010-10-20 10:49  桃子在路上  阅读(979)  评论(0)    收藏  举报

【聪明的打字员】
    阿兰是某机密部门的打字员,出于保密的需要,该部门用于输入密码的键盘是特殊设计的,键盘上没有数字键,而只有以下六个键:Swap0, Swap1, Up, Down, Left, Right,定义录入区的6个位置的编号,从左至右依次为1,2,3,4,5,6。下面列出每个键的作用:
   Swap0:按Swap0,光标位置不变,将光标所在位置的数字与录入区的1号位置的数字(左起第一个数字)交换。如果光标已经处在录入区的1号位置,则按Swap0键之后,录入区的数字不变;
  Swap1:按Swap1,光标位置不变,将光标所在位置的数字与录入区的6号位置的数字(左起第六个数字)交换。如果光标已经处在录入区的6号位置,则按Swap1键之后,录入区的数字不变;
  Up:按Up,光标位置不变,将光标所在位置的数字加1(除非该数字是9)。例如,如果光标所在位置的数字为2,按Up之后,该处的数字变为3;如果该处数字为9,则按Up之后,数字不变,光标位置也不变;
  Down:按Down,光标位置不变,将光标所在位置的数字减1(除非该数字是0),如果该处数字为0,则按Down之后,数字不变,光标位置也不变;
  Left:按Left,光标左移一个位置,如果光标已经在录入区的1号位置(左起第一个位置)上,则光标不动;
  Right:按Right,光标右移一个位置,如果光标已经在录入区的6号位置(左起第六个位置)上,则光标不动。
  当然,为了使这样的键盘发挥作用,每次录入密码之前,录入区总会随机出现一个长度为6的初始密码,而且光标出现随机位置上。当巧妙地使用上述六个特殊键之后,可以得到目标密码,这时光标允许停在任何一个位置。
  现在,阿兰有一个6位的数字密码,请编写一个程序,求出录入一个密码需要的最少的击键次数。
【输入文件】clever.in
两行,第一行为初始密码,空格后为光标位置(1-6),第二行为要输入的密码值。

【输出文件】clever.out
仅一行,为打出密码的最少击键次数。

【样例数据】
【输入】
123456 1
623453
【输出】
3

【参考程序1(盲目搜索)】

program clevertyper;
const
  max=600000;
type
  passtext=array[1..6] of byte;      {用数组存储每一个密码数字}
  tlist=record                        {结点类型}
     father:longint;
     dep:byte;
     point:1..6;
     state:passtext;
  end;
var
  source,target:passtext;                 {初始结点和目标结点}
  list:array[0..max] of tlist;        {扩展出的中间结点序列}
  head,foot,best,i:longint;
  answer:longint;
  found:boolean;
  str1:string[8];
  point0:1..6;
procedure init;                      {初始化过程}
  var
    i:byte;
  begin
    assign(input,'clever.in');
    reset(input);
    assign(output,'clever.out');
    rewrite(output);
    readln(str1);
    for i:=1 to 6 do
       val(copy(str1,i,1),source[i]);
    val(copy(str1,8,1),point0);
    readln(str1);
    for i:=1 to 6 do
       val(copy(str1,i,1),target[i]);
    fillchar(list,sizeof(list),0);
    found:=false;
    head:=0;                         {队列初始化,队首指针head,队尾指针foot}
    foot:=1;
    with list[1] do                  {初始结点作为队列第一个结点}
      begin
        state:=source;
        dep:=0;
        father:=0;
        point:=point0;
      end;
  end;
function same(a,b:passtext):boolean;
  var
    i:byte;
  begin
    same:=false;
    for i:=1 to 6 do
      if a[i]<>b[i] then exit;
    same:=true;
  end;
function notappear(newv:tlist):boolean;  {判断扩展出的结点是否已在队列中的函数}
  var
    i:longint;
  begin
    notappear:=false;
    for i:=1 to foot do
      if same(newv.state,list[i].state) and (newv.point=list[i].point)
        then exit;
    notappear:=true;
  end;
procedure add(newv:tlist);      {往队列中加入新结点过程}
  begin
    if notappear(newv)
      then begin
            inc(foot);
            list[foot]:=newv;
           end;
   end;
procedure expand(index:longint;var n:tlist);  {扩展结点过程}
  var
    i,x,y:integer;
    newv:tlist;
  begin
    for i:=1 to 6 do                   {分别应用6条规则}
     begin
       if i=1 then
          if n.point>1
            then begin
                   newv.state:=n.state;
                   newv.point:=n.point;
                   newv.state[1]:=n.state[n.point];
                   newv.state[n.point]:=n.state[1];
                 end;
       if i=2 then
          if n.point<6
            then begin
                   newv.state:=n.state;
                   newv.point:=n.point;
                   newv.state[6]:=n.state[n.point];
                   newv.state[n.point]:=n.state[6];
                 end;
       if i=3 then
          if n.state[n.point]<9
            then begin
                   newv.state:=n.state;
                   newv.point:=n.point;
                   newv.state[n.point]:=newv.state[n.point]+1;
                 end;
       if i=4 then
          if n.state[n.point]>0
            then begin
                   newv.state:=n.state;
                   newv.point:=n.point;
                   newv.state[n.point]:=newv.state[n.point]-1;
                 end;
       if i=5 then
          if n.point>1
            then begin
                   newv.state:=n.state;
                   newv.point:=n.point-1;
                 end;
       if i=6 then
          if n.point<6
            then begin
                   newv.state:=n.state;
                   newv.point:=n.point+1;
                 end;
        newv.father:=index;
        newv.dep:=n.dep+1;
        add(newv);
     end;
  end;
procedure print(index:longint);   {递归打印路径}
  var
    i,j:byte;
  begin
    if index=0  then exit;
    print(list[index].father);
    for i:=1 to 6 do
      write(list[index].state[i]);
    writeln(' ',list[index].point);
  end;
begin{main}
  init;
  repeat
    inc(head);
    if same(list[head].state,target)   {比较是否跟目标相同,相同则找到,否则扩展新结点}
       then begin
             found:=true;
             best:=list[head].dep;
             answer:=head;
             break;
            end;
    if list[foot].dep>6               {搜索树的深度超过6时,速度很慢,显示超时}
       then begin
              writeln('OverTime!');
              break;
            end;
    expand(head,list[head]);
  until (head>=foot) or (foot>max) or found;
   if found
     then begin
           writeln(best);
           print(answer);
          end
     else writeln('No Answer');
  close(input);
  close(output);
end.

【参考程序2(结构优化)】

program clevertyper;
const
  max=600000;
type
  passtext=array[1..6] of byte;      {用数组存储每一个密码数字}
  tlist=record                        {结点类型}
     step:byte;
     point:1..6;
     state:passtext;
  end;
var
  source,target:passtext;                 {初始结点和目标结点}
  list:array[0..max] of tlist;        {扩展出的中间结点序列}
  app:array[1..6,0..9,0..9,0..9,0..9,0..9,0..9] of boolean;
  head,foot:longint;
  u,v,i:byte;
  ch:char;
  point0:1..6;
begin
  assign(input,'clever.in');
  reset(input);
  for i:=1 to 6 do
    begin
      read(ch);
      source[i]:=ord(ch)-48;
    end;
  read(ch);readln(point0);
  for i:=1 to 6 do
    begin
      read(ch);
      target[i]:=ord(ch)-48;
    end;
  close(input);
  head:=0;                         {队列初始化,队首指针head,队尾指针foot}
  foot:=1;
  with list[1] do                  {初始结点作为队列第一个结点}
    begin
      state:=source;
      step:=0;
      point:=point0;
    end;
  fillchar(app,sizeof(app),false);
  while true do
   begin
    head:=head+1;
    with list[head] do
      begin
       if comparebyte(state,target,6)=0
         then begin
             assign(output,'clever.out');
             rewrite(output);
             writeln(step);
             close(output);
             break;
            end;
    {分别应用6条规则}
    {按LEFT键}
    if (point>1) and not app[point-1,state[1],state[2],state[3],state[4],state[5],state[6]]
      then begin
             foot:=foot+1;
             list[foot].state:=state;
             list[foot].step:=step+1;
             list[foot].point:=point-1;
             app[point-1,state[1],state[2],state[3],state[4],state[5],state[6]]:=true;
           end;
    {按RIGHT键}
    if (point<6) and not app[point+1,state[1],state[2],state[3],state[4],state[5],state[6]]
      then begin
             foot:=foot+1;
             list[foot].state:=state;
             list[foot].step:=step+1;
             list[foot].point:=point+1;
             app[point+1,state[1],state[2],state[3],state[4],state[5],state[6]]:=true;
           end;
    {按DOWN键}
    if state[point]>0
      then begin
            state[point]:=state[point]-1;
            if not app[point,state[1],state[2],state[3],state[4],state[5],state[6]]
              then begin
                    foot:=foot+1;
                    list[foot].state:=state;
                    list[foot].step:=step+1;
                    list[foot].point:=point;
             app[point,state[1],state[2],state[3],state[4],state[5],state[6]]:=true;
           end;
           state[point]:=state[point]+1;{还原被扩展结点的值}
          end;
    {按UP键}
    if state[point]<9
      then begin
            state[point]:=state[point]+1;
            if not app[point,state[1],state[2],state[3],state[4],state[5],state[6]]
              then begin
                    foot:=foot+1;
                    list[foot].state:=state;
                    list[foot].step:=step+1;
                    list[foot].point:=point;
             app[point,state[1],state[2],state[3],state[4],state[5],state[6]]:=true;
           end;
           state[point]:=state[point]-1;{还原被扩展结点的值}
          end;
    {按swap0键}
    u:=state[point];
    v:=state[1];
    state[1]:=u;
    state[point]:=v;
    if not app[point,state[1],state[2],state[3],state[4],state[5],state[6]]
       then begin
             foot:=foot+1;
             list[foot].state:=state;
             list[foot].step:=step+1;
             list[foot].point:=point;
             app[point,state[1],state[2],state[3],state[4],state[5],state[6]]:=true;
            end;
    {按swap1键}
    state[1]:=v;
    state[point]:=state[6];
    state[6]:=u;
    if not app[point,state[1],state[2],state[3],state[4],state[5],state[6]]
       then begin
             foot:=foot+1;
             list[foot].state:=state;
             list[foot].step:=step+1;
             list[foot].point:=point;
             app[point,state[1],state[2],state[3],state[4],state[5],state[6]]:=true;
            end;
  end;{with}
 end;{while}
end.