题意:给你三个杯子,其中第三个杯子是满的,要你倒出指定容积的水,如果不能倒出则输出最接近的值。
思路:BFS+剪枝。剪去之前到达过的状态,如果没有剪枝是不可能出现队列为空的情况的也就是只有倒出指定的水才会结束搜索,所以这里剪枝是必须的。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
struct State
{
int x[5],sum;
};
int X[5],D,_sum,_ans;
bool ok;
void Fill(int &a,int &b,int A,int B,int &sum)
{
if(a+b<=B)
{
sum+=a;
b=a+b;
a=0;
}
else
{
sum+=B-b;
a=a+b-B;
b=B;
}
}
void Judge(State ss)
{
if(ss.x[1]==D||ss.x[2]==D||ss.x[3]==D)
{
_sum=ss.sum;
_ans=D;
ok=true;
}
else
{
for(int i=1; i<=3; ++i)
if(ss.x[i]<D&&(D-ss.x[i])<(D-_ans))
{
_ans=ss.x[i];
_sum=ss.sum;
}
}
}
bool vis[201][201][201];
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d%d%d",&X[1],&X[2],&X[3],&D);
_sum=0;
_ans=0;
State st;
st.x[1]=st.x[2]=st.sum=0;
st.x[3]=X[3];
memset(vis,0,sizeof(vis));
Judge(st);
queue<State> q;
q.push(st);
ok=false;
while(!q.empty()&&!ok)
{
State tmp=q.front();
q.pop();
for(int i=1; i<=3&&!ok; ++i)
{
if(tmp.x[i])
{
for(int j=1; j<=3&&!ok; ++j)
{
if(i==j||tmp.x[j]==X[j]) continue;
State t=tmp;
Fill(t.x[i],t.x[j],X[i],X[j],t.sum);
Judge(t);
if(vis[t.x[1]][t.x[2]][t.x[3]]) continue;
else
{
q.push(t);
vis[t.x[1]][t.x[2]][t.x[3]]=true;
}
}
}
}
}
printf("%d %d\n",_sum,_ans);
}
return 0;
}