• 倒水问题 (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.
  • 相关阅读:
    nodejs学习笔记
    php操作mysql数据库
    HTML5 新特性总结
    万恶的浏览器兼容问题
    图标字体使用方法
    托管代码
    进程间通信,把字符串指针作为参数通过SendMessage传递给另一个进程,不起作用
    利用自定义消息处理函数的WPARAM或LPARAM参数传递指针
    自定义消息中如果需要定义WPARAM和LPARAM,该怎么使用和分配?
    提高VS2010运行速度的技巧+关闭拼写检查
  • 原文地址:https://www.cnblogs.com/PengBoLiuXu/p/4513560.html
Copyright © 2020-2023  润新知