题目:
题意:
有3个杯子,先告诉三个杯子的容量,初始只有第三个杯子装满水,每次只能从一个杯子往另外一个杯子倒水,要求,必须把当前杯子水倒完,或者另一个杯子倒满。问,能不能量出 D 升水?要求总倒水量最小
思路:
优先队列bfs模拟
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e2+5;
const int inf=1e9;
int t,ans[maxn],v[5],vis[maxn][maxn];
struct node{
int w[4];
int dis;
bool operator < (const node& x) const {
return dis>x.dis;
}
};
void check(node x){
for(int i=1;i<=3;i++){
int d=x.w[i];
if(ans[d]==-1||ans[d]>x.dis)ans[d]=x.dis;
}
}
void dij(int A,int B,int C,int D){
priority_queue<node>p;
memset(ans,-1,sizeof(ans));
memset(vis,0,sizeof(vis));
v[1]=A,v[2]=B,v[3]=C;
node xx;
xx.w[1]=0,xx.w[2]=0,xx.w[3]=C,xx.dis=0;
p.push(xx);
vis[0][0]=1;
while(!p.empty()){
node x=p.top();
p.pop();
check(x);//更新ans
if(ans[D]>=0)break;//找到答案
for(int i=1;i<=3;i++){//取两个杯子出来,互相倒水
for(int j=1;j<=3;j++){
if(i==j)continue;
if(x.w[i]==0||x.w[j]==v[j])continue;//不能倒
int d=v[j]-x.w[j]; //j杯子最多还能装多少水
node nx;
for(int k=1;k<=3;k++)nx.w[k]=x.w[k];//初始化下一个状态
if(d>=x.w[i])nx.w[j]=x.w[i]+x.w[j],nx.w[i]=0,nx.dis=x.dis+x.w[i];//模拟倒水
else nx.w[j]=v[j],nx.w[i]=x.w[i]-d,nx.dis=x.dis+d;
if(!vis[nx.w[1]][nx.w[2]]){//每种状态第一次到达最小
vis[nx.w[1]][nx.w[2]]=1;
p.push(nx);
}
}
}
}
for(int i=D;i>=0;i--){
if(ans[i]>=0){
printf("%d %d\n",ans[i],i);
return;
}
}
}
int main(){
scanf("%d",&t);
while(t--){
int a,b,c,d;
scanf("%d%d%d%d",&a,&b,&c,&d);
dij(a,b,c,d);
}
}