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(); } }