UVA 10603 Fill(倒水问题)

                                                                              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.


样例输入:

扫描二维码关注公众号,回复: 444563 查看本文章

2

2 3 4 2

96 97 199 62


样例输出:

2 2

9859 62


【题意】

         

          T组测试数据,每组测试数据输入4个整数,分别表示第一个杯子的容量、第二个杯子的容量、第三个杯子

  的容量、目标容量,4个整数(小于200大于0)。输出最小的总倒水量和目标容量,如果倒不出目标容量,就

  输出能倒出的小于目标容量的最大的容量的总倒水量和容量。


【分析】


           此题就是一个倒水问题,比单纯的倒水问题增加了难度:

                    1. 增加输出总的倒水量。

                    2. 容量变大了,出现的情况更多了,所以一般的dfs会超时。

                    3. 如果倒出目标容量,输出最接近且小于的目标容量的容量。 

         

         (一).  倒水过程和一般倒水问题一样,通过两层for循环实现枚举所有情况。

         (二). 借助优先队列,以总倒水量排序,节约代码的时间。

         (三). 虽然是3个水杯,但是水的总量是不变的,所以标记数组,用两个就够了。

         (四). 定义一个数组保存倒出水容量的最小总倒水量,方便输出和结束倒水。


【代码】


#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;

struct node
{
    int value;
    int dist[3];
    bool operator <(const node& a) const
    {
        return a.value<value;
    }
};
const int MAXN=200+5;
bool book[MAXN][MAXN];
int ans[MAXN],cap[3]; /* 此题ans数组用的非常好 */// ans数组保存出现过的水量的最优解

void fun(const node& p)
{
    for(int i=0;i<3;i++)
    {
        int d=p.dist[i];
        if(ans[d]<0||ans[d]>p.value)
            ans[d]=p.value;
    }
    return ;
}

void bfs(int a,int b,int c,int d)
{
    cap[0]=a;cap[1]=b;cap[2]=c;
    memset(book,0,sizeof(book));
    memset(ans,-1,sizeof(ans));
    priority_queue<node>p;
    node start;
    start.value=0;start.dist[0]=0;start.dist[1]=0;start.dist[2]=c;
    p.push(start);
    while(!p.empty())
    {
        node p1;
        p1=p.top();
        p.pop();
        fun(p1);      // 标记所有容量出现时的最优解
        if(ans[d]>=0) // 结束语句
            break;
        for(int i=0;i<3;i++)
        {
            for(int j=0;j<3;j++)
            {
                if(i==j||p1.dist[i]==0||p1.dist[j]==cap[j])
                    continue;
                int num=min(cap[j],p1.dist[i]+p1.dist[j])-p1.dist[j]; // 用的不错
                node p2=p1;
                p2.value+=num;
                p2.dist[i]-=num;
                p2.dist[j]+=num;
                if(!book[p2.dist[0]][p2.dist[1]])  // 一共3个杯子,前两个确定,就已经是唯一的
                {
                    book[p2.dist[0]][p2.dist[1]]=true;
                    p.push(p2);
                }
            }
        }
    }
    while(d>=0)  // 输出答案或者最接近的解
    {
        if(ans[d]>=0)
        {
            printf("%d %d\n",ans[d],d);
            return ;
        }
        d--;
    }
    return ;
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int a,b,c,d;
        scanf("%d %d %d %d",&a,&b,&c,&d);
        bfs(a,b,c,d);
    }
    return 0;
}


【收获】

                1.  ans数组给我的收获最大,之前看的别的代码,特别麻烦还易错,需要判断是不是目标量、分别定义

       目标量的数据和非目标量的数据,输出时判断情况,分别输出,过于繁琐。用ans数组简单明了,大神的思

       维就是屌。

                2.  num变量用的不错,之前都是用两个if语句判断分别进行倒水,用了num节约了很多代码

                3.  二维数组标记,刚做这个题时,用的三维数组标记的。没有仔细去想,由两个固定就一定可以确定

       唯一性。




猜你喜欢

转载自blog.csdn.net/disparity_cjk/article/details/52965782