倒水问题(暴力搜索)

问题背景:
有装满水的6升的杯子,空的3升杯子和1升杯子,3个杯子都没有刻度,在不使用其他道具的情况下,是否可以亮出4升的水呢?

这个问题很有趣,所以今天就写这道题。

在这种特殊情况下,求解很简单,先把6升的水分别倒入3,1 升水的杯子中,再把1升的水倒入3升的杯子中,就得到4省的水。。。

你的任务是解决 一般性的问题:设3个杯子容量分别为啊,a,b,c最初只有第三只杯子装满了c升水,其他两个杯子为空。最少要倒多少升水才能让某一个杯子的水有d升呢?如果无法做到恰好d升,就让某一个杯子里的水是d升,其中d' < d,并且尽量接近d。

1 《  a,b,c,d,《 200。要求输出最少的倒水量和目标水量d或d‘。

 

这道题对我而言是一道很好的题目,因为这是一道很抽象的题目,要转换代码如果没有看过别人怎么转换的是有一点难度,所以再打一遍思路熟悉熟悉。

假设在某一时刻,第一个杯子中有v0升水,第二个杯子中有v1升水,第3个杯子中有v2升水,那么某一时刻的系统状态为(v0,v1,v2)。  这里提到了  “状态” 这一个词,它是理解很多概念和算法的关键。它是对系统当前状态的描述,不如说  v0=6, v1=3,v2=1,那么知道了三个数据,系统的状态就能知道。

直接看代码就能知道解题思路,因为这是一道暴力解法。

代码:

#include <iostream>
#include <cstring>
#include <queue>

using namespace std;
struct node {
	int v[3], dist;
	bool operator < (const node & rhs) const {   // ********比较函数的定义 
		return dist > rhs.dist;
	}
};

const int maxn = 200 + 5;
int vis[maxn][maxn], cap[3], ans[maxn];      // vis 记录状态    cap 记录 杯子容量     

void update_ans(const node& u) {      //引用传递参数
	for(int i = 0; i < 3; i ++) {
		int d = u.v[i];                          
		if(ans[d] < 0 || u.dist < ans[d])  ans[d] = u.dist;    //更新数据 
	}
}

void solve(int a, int b, int c, int d) {
	cap[0] = a, cap[1] = b, cap[2] = c;
	memset(vis, 0, sizeof(vis));              //初始化所有数据都为零 
	memset(ans, -1, sizeof(ans));            // 初始化数组为负数 
	priority_queue<node> q;					//优先队列 

	node start;							     //初始化第一个 
	start.dist = 0;
	start.v[0] = 0;
	start.v[2] = 0;
	start.v[2] = c;
	q.push(start);

	vis[0][0] = 1;
	while(!q.empty()) {     
		node u = q.top();
		q.pop();
		update_ans(u);
		if(ans[d] >= 0) break;
		for(int i = 0; i < 3; ++i)                       //把 I 的 水 倒入  j  中 
			for(int j = 0; j < 3; j++)if(i!=j) {
					if(u.v[i] == 0 || u.v[j] == cap[j]) continue;             // 如果i没有水  或者j的水满了 
					int amount = min(cap[j],u.v[i] + u.v[j] - u.v[j]);          //能倒多少水 是多少水 
					node u2;                                        
					memcpy(&u2, &u, sizeof(u));										  //记录 
					u2.dist = u.dist + amount;			  //转移到另一个后,  
					u2.v[i] -= amount;
					u2.v[j] += amount;
					if(!vis[u2.v[0]][u2.v[1]]) {		  //如果没有这个状态, 那么将他放入队列中 
						vis[u2.v[0]][u2.v[1]] = 1;     //*****记录了两个杯子的状态就可以知道总的状态是什么 
						q.push(u2);
					}
				}

	}
	while(d >= 0){
		if(ans[d] >= 0){
			printf("%d %d\n", ans[d], d);
			return ;
		}
		d--;
	}
}
int main() {
	int t, a, b, c, d;
	scanf("%d", &t);
	while(t--){
		cin >> a >> b >> c >> d;
		solve(a, b, c, d);
	}
	return 0;
}

代码解释: 注意使用了队列queue 换成 优先队列 priority_queue,注意priority_queue的用法。

时间有限,倒水的方法就不写上去了。。。。。。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值