- 题目大意
有三个已知体积但不知刻度的杯子,前两个杯子中初始时没有水,第三个装满水,问是否可以倒出d升水,如果倒不出,则倒出一个最大的d’,使得d’<=d,并且在这个过程中要求总倒水量最少。
- 解题思路
可以用DFS加上优先队列来解决,以前两个杯子中的水量作为标记状态。只不过这次不是要求的最求最少步数,而是要求最少倒水量即可。
- 代码
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstring>
#include<stack>
#include<queue>
using namespace std;
int maps[500][500];
int cnt[500];
struct Edge
{
int m[3],sum;
Edge(int a,int b,int c,int s)
{
m[0]=a,m[1]=b,m[2]=c,sum=s;
}
bool operator <(const Edge &rhs)const{
return sum>rhs.sum;
}
};
void bfs(int a,int b,int c,int d)
{
int num[3]={a,b,c};
priority_queue<Edge>q;
memset(maps,0,sizeof(maps));
memset(cnt,-1,sizeof(cnt));
maps[0][0]=1;
q.push(Edge(0,0,c,0));
while(!q.empty())
{
Edge u=q.top();
q.pop();
for(int i=0;i<3;i++)
{
if(cnt[u.m[i]]<0||u.sum<cnt[u.m[i]])
cnt[u.m[i]]=u.sum;
}
if(cnt[d]>=0)
break;
for(int i=0;i<3;i++)
{
if(u.m[i]==num[i])
continue;
for(int j=0;j<3;j++)
{
if(i==j||u.m[j]==0)
continue;
int mid=min(num[i],u.m[j]+u.m[i])-u.m[i];
Edge tmp=u;
tmp.sum+=mid;
tmp.m[i]+=mid;
tmp.m[j]-=mid;
if(!maps[tmp.m[0]][tmp.m[1]])
{
maps[tmp.m[0]][tmp.m[1]]=1;
q.push(tmp);
}
}
}
}
while(d>=0)
{
if(cnt[d]>=0)
{
printf("%d %d\n",cnt[d],d);
return;
}
--d;
}
}
int main()
{
int a,b,c,d;
int n;
scanf("%d",&n);
while(n--)
{
scanf("%d%d%d%d",&a,&b,&c,&d);
bfs(a,b,c,d);
}
return 0;
}