J - Fill (UVA - 10603)
- 题目大意
有三个已知体积但不知刻度的杯子,前两个杯子中初始时没有水,第三个装满水,问是否可以倒出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; }