[Wikioi 1226]倒水问题

题目描述 Description

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

输入描述 Input Description

一行,三个数据,分别表示 x,y 和 z;

输出描述 Output Description

一行,输出最小步数 ,如果无法达到目标,则输出"impossible"

样例输入 Sample Input

3 22 1

样例输出 Sample Output

14

数据范围及提示 Data Size & Hint

此题数据太弱了,DFS稍微剪枝下都能过,无语

倒水一共有6种策略:

操作1:装满a桶

操作2:装满b桶

操作3:清空a桶

操作4:清空b桶

操作5:将B桶中的水倒入A桶

操作6:将A桶的水倒入B桶

每种策略在判断条件后模拟一遍就OK了,不过要注意判重

不管是DFS还是BFS,强调它的判重只需要数组就够了,没必要像ZFX童鞋那样用STL的set,由于x,y<=100,最多有10000种状态,数组不会爆

1、DFS

这里判重数组不仅要保存该结点是否访问过,而且要记录该结点的步数(即解的好坏),便于为后面循环求得最优解

#include <stdio.h>
#define MAXN 200
#define INF 10000000
int f[MAXN][MAXN],a,b,z; //f[x][y]=达到A桶内水量为x,B桶内水量为y的状态所需步骤数
void dfs(int x,int y,int step) //x=A桶内水量,y=B桶内水量,step=当前步骤数
{
	if(f[x][y]!=0&&step+1>=f[x][y]) return; //当前状态已经有解且现在的解一定比过去的解更差时,退出
	f[x][y]=step+1; //更新当前状态所需最少步骤数
	dfs(x,0,step+1); //1、清空B桶
	dfs(0,y,step+1); //2、清空A桶
	dfs(x,b,step+1); //3、装满B桶
	dfs(a,y,step+1); //4、装满A桶
	//5、将B桶倒入A桶
	if(x+y<=a)
		dfs(x+y,0,step+1);//(i)B桶倒空后A桶不会溢出
	else
		dfs(a,x+y-a,step+1); //(ii)B桶倒空后A桶会溢出,故B桶中有残留
	//6、将A桶倒入B桶
	if(x+y<=b)
		dfs(0,x+y,step+1);//(i)A桶倒空后B桶不会溢出
	else
		dfs(x+y-b,b,step+1); //(ii)A桶倒空后B桶会溢出,故A桶中有残留
}
int main()
{
	int i,j,ans=INF;
	scanf("%d%d%d",&a,&b,&z);
	dfs(0,0,0);
	for(i=0;i<=a;i++)
		if(f[i][z]!=0)
			if(f[i][z]<ans)
				ans=f[i][z]; //遍历所有B桶中达到水量z的情况,获得最优解
	for(i=0;i<=b;i++)
		if(f[z][i]!=0)
			if(f[z][i]<ans)
				ans=f[z][i]; //遍历所有B桶中达到水量z的情况,获得最优解
	if(ans==INF) printf("impossible\n");
	else printf("%d\n",ans-1);
	return 0;
}

2、BFS

BFS做法稍微复杂些,不过和DFS殊途同归,根据BFS的性质,BFS最终搜索出的结果就是最优解,判重数组只需保存每个结点是否访问过就可以了,另外BFS的判重非常重要,否则BFS将进入死循环(我刚开始的代码就是这样,调了一个多小时,ORZ)

#include <stdio.h>
#include <stdlib.h>
#include <queue>
#define MAXN 110
using namespace std;
int a,b,z,f[MAXN][MAXN]; //目标是取z L水
struct cup
{
	int x; //x桶(大桶)中的水量
    int y; //y桶(小桶)中的水量
	int sol; //sol=量出的水量
	int step; //step=倒水次数
}first,now;
queue<cup>Q;
void extend(cup in) //扩展结点
{
	if(f[in.x][in.y]!=0) return;
	f[in.x][in.y]++;
	in.step++;
	cup p=in;
	//操作1:装满a桶
	p.x=a;
	Q.push(p);
	//操作2:装满b桶
	p=in;
	p.y=b;
	Q.push(p);
	//操作3:清空a桶
	p=in;
	p.x=0;
	Q.push(p);
	//操作4:清空b桶
	p=in;
	p.y=0;
	Q.push(p);
	//操作5:将B桶中的水倒入A桶
	p=in;
	if(in.x+in.y<=a) //(i)B桶倒空后A桶不会溢出
	{
		p.x=in.x+in.y;
		p.y=0;
		Q.push(p);
	}
	else //(ii)B桶倒空后A桶会溢出,故B桶中有残留
	{
		p.x=a;
		p.y=in.x+in.y-a;
		Q.push(p);
	}
	//操作6:将A桶的水倒入B桶
	p=in;
	if(in.x+in.y<=b) //(i)A桶倒空后B桶不会溢出
	{
		p.y=in.x+in.y;
		p.x=0;
		Q.push(p);
	}
	else //(ii)A桶倒空后B桶会溢出,故A桶中有残留
	{
		p.y=b;
		p.x=in.x+in.y-b;
		Q.push(p);
	}
}
void bfs()
{
	Q.push(first);
	while(!Q.empty())
	{
		now=Q.front();
		Q.pop(); //取出队首状态
		if(now.x==z||now.y==z)
		{
			printf("%d\n",now.step);
			exit(0);
		}
		extend(now);
	}
	printf("impossible\n");
}
int main()
{
	scanf("%d%d%d",&a,&b,&z);
	first.step=0;
	first.x=0;
	first.y=0;
	bfs();
	return 0;
}

[Wikioi 1226]倒水问题

时间: 2024-08-25 16:46:06

[Wikioi 1226]倒水问题的相关文章

1226 倒水问题

1226 倒水问题 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题目描述 Description 有两个无刻度标志的水壶,分别可装 x 升和 y 升 ( x,y 为整数且均不大于 100 )的水.设另有一水 缸,可用来向水壶灌水或接从水壶中倒出的水, 两水壶间,水也可以相互倾倒.已知 x 升壶为空 壶, y 升壶为空壶.问如何通过倒水或灌水操作, 用最少步数能在x或y升的壶中量出 z ( z ≤ 100 )升的水 来. 输入描述 Input Descript

广度优先搜索 cdoevs 1226 倒水问题

cdoevs 1226 倒水问题 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题目描述 Description 有两个无刻度标志的水壶,分别可装 x 升和 y 升 ( x,y 为整数且均不大于 100 )的水.设另有一水 缸,可用来向水壶灌水或接从水壶中倒出的水, 两水壶间,水也可以相互倾倒.已知 x 升壶为空 壶, y 升壶为空壶.问如何通过倒水或灌水操作, 用最少步数能在x或y升的壶中量出 z ( z ≤ 100 )升的水 来. 输入描述 Input D

洛谷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

倒水问题 (codevs 1226) 题解

[问题描述] 有两个无刻度标志的水壶,分别可装x升和y升 ( x,y 为整数且均不大于100)的水.设另有一水缸,可用来向水壶灌水或接从水壶中倒出的水, 两水壶间,水也可以相互倾倒.已知x升壶为空壶, y升壶为空壶.问如何通过倒水或灌水操作, 用最少步数能在x或y升的壶中量出 z(z ≤ 100)升的水来. [样例输入] 3 22 1 [样例输出] 14 [解题思路] 看到求最少步数,马上想到用广度优先搜索,那么问题在于如何展开?要不要剪枝?其实,这道题是不需要任何剪枝的,只要判重就行了,那么关

hdu 1226 BFS + bfs记录路径

http://acm.hdu.edu.cn/showproblem.php?pid=1226 为了省空间,可以用vis数组初始化的时候初始化为-1, 发现一个BFS容易错的地方 开始一直WA在这里:就是我int tp=q.front();之后马上q.pop():了,然后才去判断是不是符合条件以break,这样就不能根据q.empty()==1认为没有找到ans 因为这里WA了 其实也可以vis[0] == -1来判断 比较不理解的是 当n==0的时候 %n==0的时候怎么处理 //#pragma

wikioi 1697 ⑨要写信

把n个元素的错排数记为Dn,显然D1=0,D2=1.当n≥3时,设不错排时i位置的元素为a[i],不妨设最后一个数a[n]排在了第k位,其中k≠n,也就是1≤k≤n-1.那么我们现在考虑第n位的情况. 当a[k]排在第n位时,a[n]与a[k]的位置均已确定,除了a[n]和a[k]以外还有n-2个数,其错排数为Dn-2. 当a[k]不排在第n位时,只有a[n]的位置确定(占据了k位置),那么这时的包括a[k]在内的剩下n-1个数的每一种错排,都等价于只有n-1个数时的错排(因为已经假设a[k]不

倒水问题

[题目描述] 有两个无刻度标志的水壶,分别可装x升和y升(x,y为整数且均不大于100)的水.设另有一水缸,可用来向水壶灌水或接从水壶中倒出的水,两水壶间,水也可以相互倾倒.已知x升壶为空壶,y升壶为空壶.问如何通过倒水或灌水操作,用最少步数能在x或y升的壶中量出z(z ≤ 100)升的水来. [输入描述] 一行,三个数据,分别表示x,y和z. [输出描述] 一行,输出最小步数,如果无法达到目标,则输出“impossible”. [样例输入] 3 22 1 [样例输出] 14

[Wikioi 1295]N皇后问题---两种不同的解法(复习)

题目描述 Description 在n×n格的棋盘上放置彼此不受攻击的n个皇后.按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子.n后问题等价于再n×n的棋盘上放置n个皇后,任何2个皇后不妨在同一行或同一列或同一斜线上. 输入描述 Input Description 给定棋盘的大小n (n ≤ 13) 输出描述 Output Description 输出整数表示有多少种放置方法. 样例输入 Sample Input 8 样例输出 Sample Output 92 数据范围

Wikioi 2492 树状数组+并查集(单点更新区间查询)

刚开始做的时候用线段树做的,然后就跳进坑里了--因为要开方,所以区间的值都得全部变,然后想用lazy标记的,但是发现用不了,单点更新这个用不了,然后就不用了,就T了.然后实在不行了,看了别人的题解,原来是用树状数组+并查集的方法,唉--没想到啊! 因为开方之后多次那个数就会变成1了,所以是1的时候开方下去就没用了.树状数组更新的时候就把其更新的差更新即可,太机智了这题-- 昨天做了,然后出错找了好久都找不出来,原来是把s[i]写成c[i]了,然后答案一直错,晕-- #include <iostr