UVA10603 Fill【倒水问题+优先搜索】

  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



问题链接UVA10603 Fill

题意简述

  有三个壶,容量分别是a、b和c升,开始时候第1个和第2个壶是空的,第3个壶是满水的。可以把一个壶的水倒入另一个壶中,直到倒空或将另外一个壶倒满。输入a、b、c和d,计算最少的倒水量,使得其中一个壶里有d升水。如果不能倒出d升水的话,那么找一个最大的d'<d。输出倒水量和d,如果找不到的话输出倒水量和d'。

问题分析

  这是一个倒水问题!

  将<a,b,c>看成是状态,进行状态展开搜索。开始的时候,所有水在c中,2个a和b都空着。过程中,可以将任何1个中的水倒到另外某个中,或将目标倒满,或将源倒空。因为没有刻度,只能这样。这个过程中,如果出现某个的水量等于d就找到解了。同时,也要考虑得不到d的情况,所以过程中需要将最大的d'<d记录下来。容器间水倒来倒去,每次有6种倒法,对这6种倒法进行试探即可。求的是倒水量最小,所以用分支限界法实现,倒水量最小的状态优先展开

程序说明

  搜索过的状态就不需要再搜索了,用数组notvist[][][]来标记搜索过的状态。

  这个问题的程序是先CV来的,然后做了适当的修改,参见参考链接。

参考链接HDU1495非常可乐


题记

  优秀的程序员一定是CV大师。能CV则CV的做法,可以省去许多编码和测试的时间。但是,如果出现小错误的话,找起来一样的费时


AC的C++语言程序如下:

/* UVA10603 Fill */

#include <iostream>
#include <queue>
#include <cstring>
#include <cstdio>

using namespace std;

const int MAXN = 200;

int a, b, c, d, maxd1, minamount;
bool notvist[MAXN+1][MAXN+1][MAXN+1];

struct node {
    int a, b, c, amount;
    bool operator < (const node& n) const {
        return amount > n.amount;
    }
};

int bfs()
{
    maxd1 = 0;
    minamount = 0;

    priority_queue<node> q;

    memset(notvist, true, sizeof(notvist));

    node f, v;
    f.c = c;
    f.a = 0;
    f.b = 0;
    f.amount=0;
    q.push(f);

    notvist[f.c][f.a][f.b] = false;

    while(!q.empty()) {
        f = q.top();
        q.pop();

        if(f.a == d || f.b == d || f.c == d)
            return f.amount;

        if(f.a < d && f.a > maxd1) {
            maxd1 = f.a;
            minamount = f.amount;
        }
        if(f.b < d && f.b > maxd1) {
            maxd1 = f.b;
            minamount = f.amount;
        }
        if(f.c < d && f.c > maxd1) {
            maxd1 = f.c;
            minamount = f.amount;
        }

        // c --> a
        if(f.c && a - f.a > 0) {
            if(f.c > a - f.a) {         // c > a的剩余容量
                v.c = f.c - (a - f.a);
                v.a = a;
                v.b = f.b;
                v.amount = f.amount + (a - f.a);
            } else {                    // c <= a的剩余容量
                v.c = 0;
                v.a = f.a + f.c;
                v.b = f.b;
                v.amount = f.amount + f.c;
            }
            if(notvist[v.c][v.a][v.b]) {
                notvist[v.c][v.a][v.b] = false;
                q.push(v);
            }
        }
        // c --> b
        if(f.c && b - f.b > 0) {
            if(f.c > b - f.b) {         // c > b的剩余容量
                v.c = f.c - (b - f.b);
                v.a = f.a;
                v.b = b;
                v.amount = f.amount + (b - f.b);
            } else {                    // c <= b的剩余容量
                v.c = 0;
                v.a = f.a;
                v.b = f.b + f.c;
                v.amount = f.amount + f.c;
            }
            if(notvist[v.c][v.a][v.b]) {
                notvist[v.c][v.a][v.b] = false;
                q.push(v);
            }
        }
        // a --> c
        if(f.a && c - f.c > 0) {
            if(f.a > c - f.c) {         // a > c的剩余容量
                v.c = c;
                v.a = f.a - (c - f.c);
                v.b = f.b;
                v.amount = f.amount + (c - f.c);
            } else {                    // a <= c的剩余容量
                v.c = f.c + f.a;
                v.a = 0;
                v.b = f.b;
                v.amount = f.amount + f.a;
            }
            if(notvist[v.c][v.a][v.b]) {
                notvist[v.c][v.a][v.b] = false;
                q.push(v);
            }
        }
        // a --> b
        if(f.a && b - f.b > 0) {
            if(f.a > b - f.b) {         // a > b的剩余容量
                v.c = f.c;
                v.a = f.a - (b - f.b);
                v.b = b;
                v.amount = f.amount + (b - f.b);
            } else {                    // a <= b的剩余容量
                v.c = f.c;
                v.a = 0;
                v.b = f.b + f.a;
                v.amount = f.amount + f.a;
            }
            if(notvist[v.c][v.a][v.b]) {
                notvist[v.c][v.a][v.b] = false;
                q.push(v);
            }
        }
        // b --> c
        if(f.b && c - f.c > 0) {
            if(f.b > c - f.c) {         // b > c的剩余容量
                v.c = c;
                v.a = f.a;
                v.b = f.b - (c - f.c);
                v.amount = f.amount + (c - f.c);
            } else {                    // b <= c的剩余容量
                v.c = f.c + f.b;
                v.a = f.a;
                v.b = 0;
                v.amount = f.amount + f.b;
            }
            if(notvist[v.c][v.a][v.b]) {
                notvist[v.c][v.a][v.b] = false;
                q.push(v);
            }
        }
        // b --> a
        if(f.b && a - f.a > 0) {
            if(f.b > a - f.a) {         // b > a的剩余容量
                v.c = f.c;
                v.a = a;
                v.b = f.b - (a - f.a);
                v.amount = f.amount + (a - f.a);
            } else {                    // b <= a的剩余容量
                v.c = f.c;
                v.a = f.a + f.b;
                v.b = 0;
                v.amount = f.amount + f.b;
            }
            if(notvist[v.c][v.a][v.b]) {
                notvist[v.c][v.a][v.b] = false;
                q.push(v);
            }
        }
    }

    return -1;
}

int main()
{
    int t;

    scanf("%d", &t);
    while(t--) {
        scanf("%d%d%d%d", &a, &b, &c, &d);

        int ans = bfs();

        if(ans < 0) {
            printf("%d %d\n", minamount, maxd1);
        } else
            printf("%d %d\n", ans, d);
    }

    return 0;
}


  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值