第九十三题 UVa 10603 Fill

53 篇文章 1 订阅

There are three jugs with a volume of a, b and c liters. (a, b, and c are positive integers not greater
than 200). The first and the second jug are initially empty, while the third is completely filled with
water. It is allowed to pour water from one jug into another until either the first one is empty or the
second one is full. This operation can be performed zero, one or more times.
You are to write a program that computes the least total amount of water that needs to be poured;
so that at least one of the jugs contains exactly d liters of water (d is a positive integer not greater
than 200). If it is not possible to measure d liters this way your program should find a smaller amount
of water d
′ < d which is closest to d and for which d

liters could be produced. When d

is found, your
program should compute the least total amount of poured water needed to produce d

liters in at least
one of the jugs.
Input
The first line of input contains the number of test cases. In the next T lines, T test cases follow. Each
test case is given in one line of input containing four space separated integers — a, b, c and d.
Output
The output consists of two integers separated by a single space. The first integer equals the least total
amount (the sum of all waters you pour from one jug to another) of poured water. The second integer
equals d, if d liters of water could be produced by such transformations, or equals the closest smaller
value d

that your program has found.
Sample Input
2
2 3 4 2
96 97 199 62
Sample Output
2 2
9859 62

【题目大意】
  刚开始有三个杯子,容量分别为a、b、c只有第三个杯子里面有c升的水,求最小的倒水量使得某个杯子中剩下d升的水,输出这个最小的倒水量。如果无法做到d升水。就让某个杯子里有d‘升水,其中d’<d而且尽量接近d(1<=a,b,c,d<=200)要求输出最小的倒水量和目标水量(d或者是d‘)

【分析】
  三个杯子,互相倒水,一开始我想多了,也就是说水一点也不能洒( 那么久好办了,一共三个杯子,水的总量也是知道的,前两个杯子的水确定了,这个状态也就唯一确定了 )。。。。。。。。 所以说构建隐式图,以倒水量为标准,优先队列搜索,见代码实现就ok了
  假如有相同的水杯状态,但是总的倒水量不同,那么显然只需要总倒水量小的状态往下更新就可以了,这种情况会由于优先队列的排序,以及mark的标记过滤掉后面那个“较差”的状态

//
// Created by DELL on 2020/2/15.
//C++ 优先队列默认是大根堆   重载运算符

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <queue>
#define Maxn 205
using namespace std;

struct Staus {
    int v[3],dist;// dist  表示达到该状态的最小总倒水量
    bool operator < (const Staus &a) const {
        return dist > a.dist;
    }
}staus[Maxn];
int mark[Maxn][Maxn],ans[Maxn],dist[Maxn][Maxn],val[3];
//dist 表示到达该状态所需的最小倒水量    mark标记状态是否出现过  前两个被子确定 第三个杯子也就确定

inline void Update_Ans(Staus &u) {
    for(int i=0; i<3; i++)
        if(ans[u.v[i]] < 0 || ans[u.v[i]] > u.dist) ans[u.v[i]] = u.dist;
}
// a向b 倒水   要么b倒满 要么倒空a
void solve(int a,int b,int c,int d) {
    val[0] = a; val[1] = b; val[2] = c;
    memset(ans,-1,sizeof(ans));
    memset(mark,0,sizeof(mark));
    memset(dist,-1,sizeof(dist));
    priority_queue<Staus> q;
    Staus start;
    start.dist = 0;
    start.v[0] = 0,start.v[1] = 0,start.v[2] = c;
    q.push(start);   dist[0][0] = 0;
    while(!q.empty()) {
        start = q.top(); q.pop();
        if(mark[start.v[0]][start.v[1]]) continue;
        Update_Ans(start);
        mark[start.v[0]][start.v[1]] = 1;
        if(ans[d] >= 0) break;
        for(int i=0; i<3; i++)
            for(int j=0; j<3; j++) if(i != j) {
                if(start.v[i] == 0 || start.v[j] == val[j]) continue;// i 空了  或者 j满了
                int temp = min(val[j],start.v[i] + start.v[j]) - start.v[j];
                Staus cache = start;
                cache.dist += temp;
                cache.v[i] -= temp;
                cache.v[j] += temp;
                int &d = dist[cache.v[0]][cache.v[1]];
                if(d < 0 || cache.dist < d) {
                    d = cache.dist;
                    q.push(cache);
                }
            }
    }
    while(d >= 0) {
        if(ans[d] >= 0) {
            printf("%d %d\n",ans[d],d);
            return ;
        }
        d--;
    }
}

int main(int argc,char* argv[]) {
    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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

七情六欲·

学生党不容易~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值