问题背景:
有装满水的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的用法。
时间有限,倒水的方法就不写上去了。。。。。。