最近做最短路专题训练,做了这道题。某秃子告诉我可以用优先队列优化一下,不过细想了一下似乎也没有优化太多。。
这道题的核心是把三个杯子的水量和当前已经倒得水量作为一个状态,从一个状态到下一个状态,用bfs寻找所有可能的状态。因为要求距离d最近的水量d',所以在判断的时候也要下一番功夫。当然了,剪枝是必要的。如果到达的这个状态用的水量比之前到达的时候用的多的话就不会进入队列。
PS:另外如果不使用greater而是重载小于号的话,一定要在函数名后面加上const。PPS:因为嫌麻烦重载了一下[]
#include <bits/stdc++.h>
using namespace std;
int v[201][201][201];
int ed;
struct node {
int w[3], val;
bool operator <(const node& x)const { return val < x.val; }
int& operator [](const int&x) { return w[x]; }
};
int main()
{
int T, mw[3], mn = 0x3f3f3f;
cin >> T;
int ans, wt;
while (T--)
{
ans = 0x3f3f3f3f, wt = 0;
memset(v, 0x3f, sizeof v);
cin >> mw[0] >> mw[1] >> mw[2] >> ed;
v[0][0][mw[2]] = 0;
node x = { 0,0,mw[2],0 }, t;
priority_queue<node>Q;
Q.push(x);
while (!Q.empty())
{
x = Q.top();
Q.pop();
for (int i = 0;i < 3;i++)//从杯子j往杯子i倒水
{
if (x[i] == ed)
{
if (wt < ed) { wt = ed;ans = x.val; }
ans = min(ans, x.val);
break;
}
if (wt <= x[i] && x[i] < ed)
{
if (!(x[i] == wt&&ans < x.val))
{
wt = x[i];ans = x.val;
}
}
if (x[i] == mw[i])continue;//如果满了
for (int j = 0;j < 3;j++)
{
if (i == j || x[j] == 0)continue;//如果空
t = x;
int p = min(t[j], mw[i] - t[i]);
t.val += p;
t[j] -= p;
t[i] += p;
if (v[t[0]][t[1]][t[2]] > t.val)
{
v[t[0]][t[1]][t[2]] = t.val;
Q.push(t);
}
}
}
}
if (ans == 0x3f3f3f3f) { ans = wt = 0; }
cout << ans << ' ' << wt << endl;
}
return 0;
}