https://vjudge.net/problem/UVA-10603
这个题目其实是暴力的一个典范,首先题目说了是最小倒水数,也就是总共次数中转移水的数量,bfs是找最小次数的,因此要用优先队列来改变优先级,将最小倒水数优先,然后是处理如果找不到合适的d,我们要把所有能够找到的值都存放在一个数组里面,然后遍历一次就可以了,我用的vis数组是三维的,用来表示第1,2,3个杯子的水量,和紫书上的略有不同。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <queue>
/*
2
96 97 199 62
*/
using namespace std;
int c[4];
int d;
int vis[209][209][209];
int cur[209];
struct node
{
int a[3];//三个被子的水量
int m;//倒水最小值
bool operator< (const node& h) const
{
return m>h.m;
}
} temp,k;
priority_queue <node> q;
void bfs()
{
int i,j,ans,m,p,x;
memset(vis,0,sizeof(vis));
memset(cur,-1,sizeof(cur));
while(!q.empty()) q.pop();
temp.a[0]=0;
temp.a[1]=0;
temp.a[2]=c[2];//初始值
temp.m=0;
vis[temp.a[0]][temp.a[1]][temp.a[2]]=1;
q.push(temp);
while(!q.empty())
{
temp=q.top();
q.pop();
for(i=0; i<=2; i++)
{
x=temp.a[i];
if(cur[x]<0)
{
cur[x]=temp.m;
continue;
}
cur[x]=min(cur[x],temp.m);//cur[x]表示第在x的水的时候,最小倒水量
}
for(i=0; i<=2; i++) //倒水,当i==j时代表同一杯子
{
for(j=0; j<=2; j++) //从第i个杯子倒入第j个杯子
{
k=temp;
if(i==j||k.a[i]==0||c[j]==k.a[j]) continue;
m=min(k.a[i],c[j]-k.a[j]);//看可以倒多少水
k.a[i]-=m;
k.a[j]+=m;
k.m+=m;
if(vis[k.a[0]][k.a[1]][k.a[2]]) continue;
q.push(k);
vis[k.a[0]][k.a[1]][k.a[2]]=1;
}
}
}
for(i=d;i>=0;i--)
{
if(cur[i]>=0)
{
printf("%d %d\n",cur[i],i);
break;
}
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d%d",&c[0],&c[1],&c[2],&d);
bfs();
}
}