基本上是比着别人的代码自己写了一遍。思路就是一个bfs,方法感觉和uva 439 Knight Moves很类似,之前还不是很理解为什么非要有一个队列来存各种状态,原因就是从最初的0,0,b到倒水,可以形成几种状态,把这几种状态用队列存起来,利用队列先进先出的特性,一次对每一种状态进行拓展。判断可行的条件是:
1.这个状态未曾被访问到;
2.从a杯到b杯倒水时,b杯还是未满的,a杯不是空的;
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<queue>
const int INF = 0x3f3f3f3f;
using namespace std;
int jug[3],d,vis[210][210][210],flag,ans;
typedef struct node
{
int v[3];
int cost;
} node;
node a,b;
queue<node> q;
void dfs()
{
memset(vis,0,sizeof(vis));
while(!q.empty())
q.pop();
flag=0;ans=INF;
a.v[0]=0;
a.v[1]=0;
a.v[2]=jug[2];
a.cost=0;
vis[0][0][a.v[2]]=1;
q.push(a);
while(!q.empty())
{
a=q.front();
q.pop();
for(int i=0; i<3; i++)
{
if(a.v[i]==d)
{
flag=1;
ans=min(ans,a.cost);
break;
}
else
for(int j=0; j<3; j++)
{
if(i==j) continue;
b=a;
if(b.v[i]&&jug[j]-b.v[j])
{
int m=min(b.v[i],jug[j]-b.v[j]);
b.cost+=m;
b.v[i]-=m;
b.v[j]+=m;
if(!vis[b.v[0]][b.v[1]][b.v[2]])
{
vis[b.v[0]][b.v[1]][b.v[2]]=1;
q.push(b);
}
}
}
}
}
}
int main()
{
//freopen("in.txt","r",stdin);
int cas;
scanf("%d",&cas);
while(cas--)
{
scanf("%d%d%d%d",&jug[0],&jug[1],&jug[2],&d);
dfs();
while(1)
{
if(flag)
break;
d--;
dfs();
}
printf("%d %d\n",ans,d);
}
return 0;
}