题意:给三个杯子,第1个第2个空,第三个装满水,每次操作是一个杯子向另一个杯子倒水直到其中一个杯子为空或者另一个杯子倒满,求使其中一个杯子最接近d的最小倒水流量
解:最短路;
#include <iostream> #include <bits/stdc++.h> using namespace std; const int N = 500; const int inf = 0x3f3f3f3f; const int maxn=1e6+2; typedef long long LL; struct node { int v[4],cnt; bool operator <(const node &x)const { return cnt>x.cnt; } }; int a, b, c, d; int vis[N][N], ans[N]; void get(node x) { int cnt=x.cnt; if(ans[x.v[1]]==-1||ans[x.v[1]]>cnt) ans[x.v[1]]=cnt; if(ans[x.v[2]]==-1||ans[x.v[2]]>cnt) ans[x.v[2]]=cnt; if(ans[x.v[3]]==-1||ans[x.v[3]]>cnt) ans[x.v[3]]=cnt; return ; } void bfs() { int cap[4]; cap[1]=a,cap[2]=b,cap[3]=c; memset(vis,0,sizeof(vis)); memset(ans,-1,sizeof(ans)); node s1; s1.cnt=0,s1.v[1]=0,s1.v[2]=0,s1.v[3]=c; vis[0][0]=1; priority_queue<node>q; q.push(s1); while(!q.empty()) { node tmp=q.top();q.pop(); get(tmp); if(ans[d]!=-1) { printf("%d %d\n",ans[d],d); return ; } for(int i=1;i<=3;i++) { if(tmp.v[i]==0) continue; for(int j=1;j<=3;j++) { if(i==j) continue; if(tmp.v[j]==cap[j]) continue; int mint=min(tmp.v[i],cap[j]-tmp.v[j]); node s2=tmp; s2.cnt+=mint,s2.v[i]-=mint,s2.v[j]+=mint; if(!vis[s2.v[1]][s2.v[2]])vis[s2.v[1]][s2.v[2]]=1, q.push(s2); } } } while(d>=0) { if(ans[d]!=-1) { printf("%d %d\n",ans[d],d); return ; } d--; } } int main() { int t; scanf("%d", &t); while(t--) { scanf("%d %d %d %d", &a,&b,&c,&d); bfs(); } return 0; }