倒水问题 (codevs 1226) 题解

【问题描述】

     有两个无刻度标志的水壶,分别可装x升和y升 ( x,y 为整数且均不大于100)的水。设另有一水缸,可用来向水壶灌水或接从水壶中倒出的水, 两水壶间,水也可以相互倾倒。已知x升壶为空壶, y升壶为空壶。问如何通过倒水或灌水操作, 用最少步数能在x或y升的壶中量出 z(z ≤ 100)升的水来。

【样例输入】

    3 22 1

【样例输出】

    14

【解题思路】

     看到求最少步数,马上想到用广度优先搜索,那么问题在于如何展开?要不要剪枝?其实,这道题是不需要任何剪枝的,只要判重就行了,那么关键就在于如何展开。

     对于x壶和y壶,设它们壶中各装了a,b升水,那么一共有以下六种操作:

    若a>0且b<y,那么可以用x向y中倾倒min(a,y-b)升水,此时,x中剩余a-min(a,y-b)升水,y中剩余b+min(a,y-b)升水,同理,当a<x,b>0时可以反操作。

    若a>0时,可将x向水缸中倒出a升水,此时x中没有水,y中不变,若b>0时也可反操作。

    若a<x时,可从水缸中倒出x-a升水至x中,此时x中有x升水,y中不变,b<y时也可反操作。

    根据这六种操作,我们如何拓展的问题就解决了。

【代码实现】

  1 uses math;
  2 type rec=record
  3      dep,x,y:longint;
  4 end;
  5 var a:array[1..1000] of rec;
  6     f:array[0..100,0..100] of boolean;
  7     h,r,x,y,z,xx,yy:longint;
  8 begin
  9  readln(x,y,z);
 10  fillchar(f,sizeof(f),true);
 11  f[0,0]:=false;
 12  h:=0;r:=1;
 13  while h<>r do
 14   begin
 15    inc(h);
 16    if (a[h].x>=0)and(a[h].y<=y) then
 17     begin
 18      inc(r);
 19      a[r]:=a[h];
 20      a[r].dep:=a[h].dep+1;a[r].x:=a[h].x-min(a[h].x,y-a[h].y);a[r].y:=a[h].y+min(a[h].x,y-a[h].y);
 21      if not(f[a[r].x,a[r].y]) then
 22       dec(r)
 23      else
 24       f[a[r].x,a[r].y]:=false;
 25     end;
 26    if (a[r].x=z)or(a[r].y=z) then
 27     begin
 28      writeln(a[r].dep);
 29      exit;
 30     end;
 31    if (a[h].x<=x)and(a[h].y>=0) then
 32     begin
 33      inc(r);
 34      a[r]:=a[h];
 35      a[r].dep:=a[h].dep+1;a[r].x:=a[h].x+min(a[h].y,x-a[h].x);a[r].y:=a[h].y-min(a[h].y,x-a[h].x);
 36      if not(f[a[r].x,a[r].y]) then
 37       dec(r)
 38      else
 39       f[a[r].x,a[r].y]:=false;
 40     end;
 41    if (a[r].x=z)or(a[r].y=z) then
 42     begin
 43      writeln(a[r].dep);
 44      exit;
 45     end;
 46    if a[h].x>=0 then
 47     begin
 48      inc(r);
 49      a[r]:=a[h];
 50      a[r].dep:=a[h].dep+1;a[r].x:=0;
 51      if not(f[a[r].x,a[r].y]) then
 52       dec(r)
 53      else
 54       f[a[r].x,a[r].y]:=false;
 55     end;
 56    if (a[r].x=z)or(a[r].y=z) then
 57     begin
 58      writeln(a[r].dep);
 59      exit;
 60     end;
 61    if a[h].x<=x then
 62     begin
 63      inc(r);
 64      a[r]:=a[h];
 65      a[r].dep:=a[h].dep+1;a[r].x:=x;
 66      if not(f[a[r].x,a[r].y]) then
 67       dec(r)
 68      else
 69       f[a[r].x,a[r].y]:=false;
 70     end;
 71    if (a[r].x=z)or(a[r].y=z) then
 72     begin
 73      writeln(a[r].dep);
 74      exit;
 75     end;
 76    if a[h].y>=0 then
 77     begin
 78      inc(r);
 79      a[r]:=a[h];
 80      a[r].dep:=a[h].dep+1;a[r].y:=0;
 81      if not(f[a[r].x,a[r].y]) then
 82       dec(r)
 83      else
 84       f[a[r].x,a[r].y]:=false;
 85     end;
 86    if (a[r].x=z)or(a[r].y=z) then
 87     begin
 88      writeln(a[r].dep);
 89      exit;
 90     end;
 91    if a[h].y<=y then
 92     begin
 93      inc(r);
 94      a[r]:=a[h];
 95      a[r].dep:=a[h].dep+1;a[r].y:=y;
 96      if not(f[a[r].x,a[r].y]) then
 97       dec(r)
 98      else
 99       f[a[r].x,a[r].y]:=false;
100     end;
101    if (a[r].x=z)or(a[r].y=z) then
102     begin
103      writeln(a[r].dep);
104      exit;
105     end;
106   end;//六种展开方式,每次展开后都要判重,然后看是否达到目标
107  writeln('impossible');
108 end.

 

你可能感兴趣的:(倒水问题 (codevs 1226) 题解)