UVA10603
并没有A。。。但注释大概还是可以给搭嘎提供点思路的
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cstdio>
using namespace std;
struct Node
{
int v[3],dist; //dist该状态倒出的水量,v[3]记录每个杯子里的水量
bool operator<(const Node &rs)const
{
return dist>rs.dist; //
}
};
const int N=210;
bool vis[N][N]; //i,j代表第0个杯子和第1个杯子的剩余水量,因为知道总和,所以可以用两个杯子的剩余水量来代表三个杯子
int cap[3];
int ans[N]; //得到水量i需要倒出的最小水量ans[i] 目标求得ans[d]
void update_ans(const Node& u)//可以获得状态u下三个杯子里水量的水
{
for(int i=0;i<3;++i)
{
int k=u.v[i];
if(ans[k]<0||u.dist<ans[k]) ans[k]=u.dist;
}
}
void solve(int a,int b,int c,int d)
{
memset(ans,-1,sizeof(ans));
memset(vis,false,sizeof(vis));
cap[0]=a;cap[1]=b;cap[2]=c;
Node s;
s.v[0]=0;s.v[1]=0;s.v[2]=c;s.dist=0;
priority_queue<Node> q;
q.push(s);
vis[a][b]=true;
while(!q.empty())
{
Node tmp=q.top();
q.pop();
update_ans(tmp);
if(ans[d]>=0) break; //目标水量已获得 否则的话开始倒水
for(int i=0;i<3;++i) //从i向j倒水
for(int j=0;j<3;++j)
{
if(i==j) continue;
if(!tmp.v[i]||tmp.v[j]==cap[j]) continue; //i是空的或者j是满的
int amount=min(cap[j],tmp.v[i]+tmp.v[j])-tmp.v[j];//如果i杯和j杯剩的水加起来没有cap[j]大,那么能增加的水就是v[i]
//否则能增加的水就是cap[j]-v[j]
Node u;
memcpy(&u,&tmp,sizeof(tmp));
u.v[i]-=amount;
u.v[j]+=amount;
u.dist=tmp.dist+amount;
if(!vis[u.v[0]][u.v[1]])
{
q.push(u);
vis[u.v[0]][u.v[1]]=true;
}
}
}
// cout<<d<<endl;
// cout<<ans[d]<<endl;
while(d>=0)
{
if(ans[d]>=0) {printf("%d %d\n",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);
solve(a,b,c,d);
}
return 0;
}