倒水问题 (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.

 

你可能感兴趣的:(code)