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

量水问题

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

【量水问题】
    有两个无刻度的量杯A和B,其容积分别为m升和n升(m>n),现在允许用量杯从水缸里取水或将水倒回水缸里,而且两个量杯中的水也可以相互倾倒,试设计计算机程序求出在m升的量杯中准确量得k升(k<n<m)所需的最少操作步数。 (每一个取水或倒水都算一个操作步数)
 

【输入文件】ls.in
仅一行,三个数,分别为m,n,k。

【输出文件】ls.out
仅一行,为最少步数。

【样例数据】
【输入】
4 3 2
【输出】
6

【提示:可以利用宽度搜索求解】

【参考程序】

program liangshui;
const
  max=600000;
type
    tlist=record                        {结点类型}
     father:longint;
     dep:byte;
     a:integer;
     b:integer;
    end;
var
  list:array[0..max] of tlist;        {扩展出的中间结点序列}
  head,foot,best,i:longint;
  m,n,k:integer;
  answer:longint;
  found:boolean;
procedure init;                      {初始化过程}
  var
    i:byte;
  begin
    assign(input,'ls.in');
    reset(input);
    assign(output,'ls.out');
    rewrite(output);
    fillchar(list,sizeof(list),0);
    found:=false;
    head:=0;                         {队列初始化,队首指针head,队尾指针foot}
    foot:=1;
    with list[1] do                  {初始结点作为队列第一个结点}
      begin
        a:=0;
        b:=0;
        dep:=0;
        father:=0;
      end;
    readln(m,n,k)
  end;
function notappear(newv:tlist):boolean;  {判断扩展出的结点是否已在队列中的函数}
  var
    i:longint;
  begin
    notappear:=false;
    for i:=1 to foot do
      if (newv.a=list[i].a) and (newv.b=list[i].b)
        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 oldv:tlist);  {扩展结点过程}
  var
    i:integer;
    newv:tlist;
  begin
    for i:=1 to 6 do                   {分别应用6条规则}
     begin
       if i=1 then
          if oldv.a<>0                                    {把a量筒倒空}
            then begin newv.a:=0;newv.b:=oldv.b;end;
       if i=2 then
          if oldv.a<>m                                    {把a量筒灌满}
            then begin newv.a:=m;newv.b:=oldv.b;end;
       if i=3 then
          if oldv.b<>0                                    {把b量筒倒空}
            then begin newv.b:=0;newv.a:=oldv.a;end;
       if i=4 then
          if oldv.a<>n                                    {把b量筒灌满}
            then begin newv.a:=n;newv.a:=oldv.a;end;
       if i=5 then
          if (oldv.a<>0) and (oldv.b<>n)                     {把a量筒往b量筒倒水}
            then if oldv.a+oldv.b>=n                         {判断a往b倒时b能否全部装下}
                   then begin newv.b:=n;newv.a:=oldv.a-(n-oldv.b);end
                   else begin newv.a:=0;newv.b:=oldv.a+oldv.b;end;
       if i=6 then
          if (oldv.a<>m) and (oldv.b<>0)                     {把b量筒往a量筒倒水}
            then if oldv.a+oldv.b>=m                         {判断b往a倒时a能否全部装下}
                   then begin newv.a:=m;newv.b:=oldv.b-(m-oldv.a);end
                   else begin newv.b:=0;newv.a:=oldv.a+oldv.b;end;
        newv.father:=index;
        newv.dep:=oldv.dep+1;
        add(newv);
     end;
  end;
procedure print(index:longint);   {递归打印路径}
  var
    i,j:byte;
  begin
    if index=0  then exit;
    print(list[index].father);
    writeln(list[index].a,' ',list[index].b);
  end;
begin{main}
  init;
  repeat
    inc(head);
    if list[head].a=k   {比较是否跟目标相同,相同则找到,否则扩展新结点}
       then begin
             found:=true;
             best:=list[head].dep;
             answer:=head;
             break;
            end;
    if list[foot].dep>100
       then begin
              writeln('OverTime!');
              break;
            end;
    expand(head,list[head]);
    {writeln(list[head].a,' ',list[head].b);}
  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.