题目大意:有三个已知体积但不知刻度的杯子,前两个杯子中初始时没有水,第三个装满水,问是否可以倒出d升水,如果倒不出,则倒出一个最大的d’,使得d’<=d,并且在这个过程中要求总倒水量最少。
题目分析:广搜,以前两个杯子中的水量作为标记状态。只不过这次不是要求的最求最少步数,而是要求最少倒水量。
代码如下:
# include<iostream> # include<cstdio> # include<queue> # include<cstring> # include<algorithm> using namespace std; struct Node { int v[3],tot; Node(int a,int b,int c,int t){v[0]=a,v[1]=b,v[2]=c,tot=t;} bool operator <(const Node &rhs) const { return tot>rhs.tot; } }; int vis[201][201],ans[201]; void bfs(int a,int b,int c,int d) { int pal[3]={a,b,c}; priority_queue<Node>q; memset(vis,0,sizeof(vis)); memset(ans,-1,sizeof(ans)); vis[0][0]=1; q.push(Node(0,0,c,0)); while(!q.empty()) { Node u=q.top(); q.pop(); for(int i=0;i<3;++i) if(ans[u.v[i]]<0||u.tot<ans[u.v[i]]) ans[u.v[i]]=u.tot; if(ans[d]>=0) break; for(int i=0;i<3;++i){ if(u.v[i]==pal[i]) continue; for(int j=0;j<3;++j){ if(i==j||u.v[j]==0) continue; int m=min(pal[i],u.v[j]+u.v[i])-u.v[i]; Node nxt=u; nxt.tot+=m; nxt.v[i]+=m; nxt.v[j]-=m; if(!vis[nxt.v[0]][nxt.v[1]]){ vis[nxt.v[0]][nxt.v[1]]=1; q.push(nxt); } } } } while(d>=0){ if(ans[d]>=0){ printf("%d %d ",ans[d],d); return ; } --d; } } int main() { int T,a,b,c,d; scanf("%d",&T); while(T--) { scanf("%d%d%d%d",&a,&b,&c,&d); bfs(a,b,c,d); } return 0; }