倒水问题 (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.
时间: 2024-10-05 08:34:04

倒水问题 (codevs 1226) 题解的相关文章

洛谷P1432 倒水问题(CODEVS.1226)

To 洛谷.1432 倒水问题 题目背景 In the movie "Die Hard 3", Bruce Willis and Samuel L. Jackson were confronted with the following puzzle. They were given a 3-gallon jug and a 5-gallon jug and were asked to fill the 5-gallon jug with exactly 4 gallons. This

hdu_5881_Tea(xjb猜)

题目链接:hdu_5881_Tea 题意: 有一壶水, 体积在 L 和 R 之间, 有两个杯子, 你要把水倒到两个杯子里面, 使得杯子水体积几乎相同(体积的差值小于等于1), 并且使得壶里剩下水体积不大于1. 你无法测量壶里剩下水的体积, 问最小需要倒水的次数. 题解: 我是xjb猜的,下面附上ICPCcamp的题解 考虑倒水的大致过程,L = 0 和 L = 1 的情况应该是等价的,所以不妨设 L >0.首先向一个杯子倒 L/2升水,再往另一个杯子倒 L/2+1升水.接下来就来回往两个杯子里倒

HDU 5881 Tea -2016 ICPC 青岛赛区网络赛

题目链接 题意:有一壶水, 体积在 L和 R之间, 有两个杯子, 你要把水倒到两个杯子里面, 使得杯子水体积几乎相同(体积的差值小于等于1), 并且使得壶里剩下水体积不大于1. 你无法测量壶里剩下水的体积, 问最小需要倒水的次数. 题解:考虑倒水的大致过程,L = 0 和 L = 1 的情况应该是等价的,所以不妨设 L > 0.首先向一个杯子倒 L/2 升水,再往另一个杯子倒  L/2+1 升水.接下来就来回往两个杯子里倒 2 升,直到倒空为止.这样就很容易分析出需要倒水的次数.唯一注意的是最后

code1052 地鼠游戏

贪心算法,从后往前 来自codevs的题解: 我的纠结思考过程:如果每一秒都没有重复的地鼠出现 那么肯定是一个一个挨着打如果有重复的地鼠 那么要考虑打那个更优 当然是选分值最大的 单纯这样想很合理 但是忽略了一种情况 分值小的地鼠早出现了 而后面重复的地鼠都比这个早出现的地鼠分值大我们就不能去打这只小的 而是把时间去用在打后面重复的地鼠身上如 1 2 2    5 6 7 那么按照地鼠的分值排序 然后挨着打怎么样也不对 因为分值大的地鼠也有可能停留时间长 我们早打了他 会导致时间短的地鼠没法打

code1006 等差数列

我绞尽脑汁想一个更好的算法,然而不能如愿,只好写一个n^3的了 很简单,就是暴力搜索(还好n<100) 先排序,然后循环i=1ton,j=i+1ton 把a[i]a[j]确定为等差数列开始的两个数,确定公差,然后用search()搜这个数列的长度 取所有的最大值即可 代码如下: #include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<algo

trie tree

trie树也叫字典树,前缀树 字典树(Trie)有如下几条性质 结点不存值,依靠树枝(边)存值 从根节点到某一处标记点为一个单词 每个结点到其子节点的边上的值各不相同 插入和查询复杂度均为O(mn),m为字符串个数,n为字符串平均长度 树深度由最长字符串决定 依次便可做出trie树的结点结构 struct trie{ int cnt=0; bool word=0; trie * son[26]={0}; }; 让我们依次价绍这几个成员的含义 cnt 这条边上有几个单词经过,即有多少指定的前缀相同

codevs 1512 转向游戏 题解

Codevs 1512转向游戏 题解 时间限制: 1 s 空间限制: 1000 KB 题目等级 : 白银 Silver 题解 题目描述 Description 小明自认为方向感很好,请小红来测试.小红先让小明面对北方立正站好,然后发出"向左转""向右转"或"向后转"的命令.每个命令执行后,小明都正确地说出了他面对的方向.小红的命令共N个(1≤n≤10000),请你统计小明说[南]的次数. 命令是以数字方式表达: 0---向左转 1---向右转 2

codevs 1506 传话 题解

Codevs 1506传话 题解 1506 传话--这个题目的解法很多,你能想到几种? 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 白银 Silver 题解 题目描述 Description 一个朋友网络,如果a认识b,那么如果a第一次收到某个消息,那么会把这个消息传给b,以及所有a认识的人. 如果a认识b,b不一定认识a. 所有人从1到n编号,给出所有"认识"关系,问如果i发布一条新消息,那么会不会经过若干次传话后,这个消息传回给了i,1<=i<=n

CODEVS 1048 石子归并 题解

此文为博主原创题解,转载时请通知博主,并把原文链接放在正文醒目位置. 题目链接:http://codevs.cn/problem/1048/ 题目描述 Description 有n堆石子排成一列,每堆石子有一个重量w[i], 每次合并可以合并相邻的两堆石子,一次合并的代价为两堆石子的重量和w[i]+w[i+1].问安排怎样的合并顺序,能够使得总合并代价达到最小. 输入描述 Input Description 第一行一个整数n(n<=100) 第二行n个整数w1,w2...wn  (wi <=