POJ - 3414 Pots (kuangbin - 简单搜索)

题目描述(已转换成中文)

  小明给你两个容器,分别能装下A升水和B升水,并且可以进行以下操作:
  FILL(i) 将第i个容器从水龙头里装满(1 ≤ i ≤ 2);
  DROP(i) 将第i个容器抽干
  POUR(i,j) 将第i个容器里的水倒入第j个容器(这次操作结束后产生两种结果,一是第j个容器倒满并且第i个容器依旧有剩余,二是第i个容器里的水全部倒入j中,第i个容器为空)
  现在要求你写一个程序,来找出能使其中任何一个容器里的水恰好有C升,找出最少操作数并给出操作过程

输入格式

  有且只有一行,包含3个A,B,C(1<=A,B<=100,C<=max(A,B))

输出格式

  第一行包含一个数表示最小操作数K
  随后K行每行给出一次具体操作,如果有多种答案符合最小操作数,输出他们中的任意一种操作过程,如果你不能使两个容器中的任意一个满足恰好C升的话,输出“impossible”

输入输出样例
输入

3 5 4

输出

6
FILL(2)
POUR(2,1)
DROP(1)
POUR(2,1)
FILL(2)
POUR(2,1)

题目链接

分析:

  这道题要用到暴搜的思想,我用的是bfs解决问题,首先由题意得我们每一次操作都有6中选择:把i容器倒满、把j容器倒满、把i容器抽干、把j容器抽干、把i容器的水倒出j容器、把j容器的水倒入i容器。定义一个node结构体,结构体中,x和y分别表示每一次操作之后a容器和b容器分别有多少水量,ans表示进行的操作数,整型数组u表示前i次操作是什么,前i - 1次的具体操作是保存在刚从队首被弹出的节点里(队首元素的u数组中u[0] ~ u[i - 1]分别表示即保留了下标是前i - 1的数组元素,接着更新u[i]记录这一轮是什么操作),这样就能实现一个节点保存了前面的i次具体操作,主函数先输入两个容器的体积a和b,以及想要得到的水量c,另外,还要在主函数外定义一个vis二维数组,标记某种情况是否出现过,vis[i][j] == 1代表容器a中有i升水,容器b中有j升水,避免后续再次进行的操作得到的结果之前出现过,最后得到的答案不是最小操作次数。
  调用bfs函数,把容器a和b水量都为零的初始情况压入队列,不断弹出队首元素,对队首元素进行处理,把队首节点的u数组(保存了之前的具体操作)的前i - 1个元素都赋值给新的节点,接着u[i]保存的是最新操作,更新步长并把节点压入队列;若遇到符合预期情况的水量,则输出步长(操作次数),并依次输出u数组对应的操作;若队列已经为空,还没有遇到符合预期情况的水量,则输出impossible。

这道题需要注意的地方:

  对于每轮操作,我们有6种选择,并由u数组记录之前的具体操作,我们定义f[6][10]= {“FILL(1)”, “FILL(2)”, “POUR(1,2)”, “POUR(2,1)”, “DROP(1)”, “DROP(2)”},u数组的元素下标只要取0 ~ 5就能正序保存从初始到当前的具体操作,当遇到符合预期情况的水量时,依次输出u数组中对应的操作printf("%s\n", f[n.u[i]])。

代码如下:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;
typedef long long LL;
int vis[105][105];
int flag;
int a, b, c, i;
char f[6][10]= {"FILL(1)", "FILL(2)", "POUR(1,2)", "POUR(2,1)", "DROP(1)", "DROP(2)"};
int read(){
	int x, f = 1;
	char ch;
	while(ch = getchar(), ch < '0' || ch > '9') if(ch == '-') f = -1;
	x = ch - '0';
	while(ch = getchar(), ch >= '0' && ch <= '9') x = x * 10 + ch - 48;
	return x * f;
}
struct node{
	int x, y, ans;
	int u[105];
};
void bfs(){
	queue <node> s;
	node n, m;
	n.x = 0;
	n.y = 0;
	n.ans = 0;
	n.u[0] = 0;
	s.push(n);
	vis[0][0] = 1;
	while(!s.empty()){
		n = s.front();
		s.pop();
		if(n.x == c || n.y == c){
			flag = 1;
			printf("%d\n", n.ans);
			for(i = 1; i <= n.ans; i++){
				printf("%s\n",  f[n.u[i]]);
			}
			return;
		}
		for(i = 0; i < 6; i++){
			m.ans = n.ans + 1;
			m.x = 0;
			m.y = 0;
			for(int j = 1; j <= n.ans; j++) m.u[j] = n.u[j];
			m.u[m.ans] = i;
			if(i == 0 && n.x != a){						//FILL(1)
				m.x = a;
				m.y = n.y;
			}
			else if(i == 1 && n.y != b){				//FILL(2)
				m.y = b;
				m.x = n.x;
			}
			else if(i == 2 && n.x && n.y != b){			//POUR(1,2)
				if(n.x + n.y > b){
					m.x = n.x + n.y - b;
					m.y = b;
				}
				else{
					m.x = 0;
					m.y = n.x + n.y;
				}
			}
			else if(i == 3 && n.y && n.x != a){			//POUR(2,1)
				if(n.x + n.y > a){
					m.x = a;
					m.y = n.x + n.y - a;
				}
				else{
					m.y = 0;
					m.x = n.x + n.y;
				}
			}
			else if(i == 4 && n.x){						//DROP(1)
				m.x = 0;
				m.y = n.y;
			}
			else if(i == 5 && n.y){						//DROP(2)
				m.y = 0;
				m.x = n.x;
			}
			if(!vis[m.x][m.y]){
				vis[m.x][m.y] = 1;
				s.push(m);
			}
		}
	}
}
int main(){
	a = read(), b = read(), c = read();
	bfs();
	if(!flag) printf("impossible\n");
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值