題目:倒水問題,有已知容量的三個杯子,前兩個是空的最後的是滿的。
每次可以將一杯水倒向另一杯,只可能是全部倒進去,或者被倒的杯子滿了。
求到達目標,最小的移動水量,如果沒有目標求出不超過的最大值。
分析:圖論、搜索。利用優先隊列(移動水的量為條件)bfs求解即可。
說明:注意使用memset會超時╮(╯▽╰)╭。
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
using namespace std;
class node
{
public:
int jugs[3];
int total;
node(){};
node(int a, int b, int c, int d)
{
jugs[0] = a;
jugs[1] = b;
jugs[2] = c;
total = d;
}
bool operator < (const node & x) const
{
return total > x.total;
}
};
int visit[222][222][222];
node bfs(int jugs[], int d)
{
for (int i = 0; i <= jugs[0]; ++ i) {
for (int j = 0; j <= jugs[1]; ++ j) {
for (int k = 0; k <= jugs[2]; ++ k) {
visit[i][j][k] = 0;
}
}
}
priority_queue<node> Q;
Q.push(node(0, 0, jugs[2], 0));
visit[0][0][jugs[2]] = 1;
node ans(0, 0, 0, 0);
if (jugs[2] <= d) {
ans.jugs[2] = jugs[2];
}
while (!Q.empty()) {
node New, now = Q.top();Q.pop();
if (now.jugs[0] == d || now.jugs[1] == d || now.jugs[2] == d) {
now.jugs[2] = d;
return now;
}
for (int i = 0 ; i < 3; ++ i) {
if (now.jugs[i] < d && now.jugs[i] > ans.jugs[2]) {
ans.jugs[2] = now.jugs[i];
ans.total = now.total;
}
}
// 将 j 倒入 i
for (int i = 0; i < 3; ++ i) {
for (int j = 0; j < 3; ++ j) {
if (i != j) {
if (now.jugs[i] + now.jugs[j] > jugs[i]) {
New.jugs[i] = jugs[i];
New.jugs[j] = now.jugs[i] + now.jugs[j] - jugs[i];
New.jugs[3-i-j] = now.jugs[3-i-j];
New.total = now.total + jugs[i] - now.jugs[i];
}else {
New.jugs[i] = now.jugs[i] + now.jugs[j];
New.jugs[j] = 0;
New.jugs[3-i-j] = now.jugs[3-i-j];
New.total = now.total + now.jugs[j];
}
if (!visit[New.jugs[0]][New.jugs[1]][New.jugs[2]]) {
visit[New.jugs[0]][New.jugs[1]][New.jugs[2]] = 1;
Q.push(New);
}
}
}
}
}
return ans;
}
int main()
{
int n, jugs[3], d;
scanf("%d",&n);
while (n --) {
scanf("%d%d%d%d", &jugs[0], &jugs[1], &jugs[2], &d);
node ans = bfs(jugs, d);
printf("%d %d\n", ans.total, ans.jugs[2]);
}
return 0;
}