uva 10090 marbles

该问题描述了一个需要以最低成本购买两种不同类型的盒子来存储大理石的情况。类型1的盒子每个成本c1,能装n1个大理石,类型2的盒子每个成本c2,能装n2个。输入包含多个测试用例,每个用例给出大理石数量n,以及两种盒子的成本和容量。输出应提供一种解决方案,即每种类型盒子所需的数量,如果存在,则保证盒子被填满且成本最低。如果不存在解决方案,则输出"failed"。

Problem F

Marbles

Input: standard input

Output: standard output

 

I have some (say, n) marbles (small glass balls) and I am going to buy some boxes to store them. The boxes are of two types:

 

Type 1: each box costs c1 Taka and can hold exactly n1 marbles

Type 2: each box costs c2 Taka and can hold exactly n2 marbles

 

 

I want each of the used boxes to be filled to its capacity and also to minimize the total cost of buying them. Since I find it difficult for me to figure out how to distribute my marbles among the boxes, I seek your help. I want your program to be efficient also.

 

Input

The input file may contain multiple test cases. Each test case begins with a line containing the integer n (1 <= n <= 2,000,000,000). The second line contains c1 and n1, and the third line contains c2 and n2. Here, c1c2n1 and nare all positive integers having values smaller than 2,000,000,000.

 

A test case containing a zero for n in the first line terminates the input.

 

Output

For each test case in the input print a line containing the minimum cost solution (two nonnegative integers m1 and m2, where mi = number of Type i boxes required) if one exists, print "failed" otherwise.

 

If a solution exists, you may assume that it is unique.

 

Sample Input

43
1 3
2 4
40
5 9
5 12
0

 

Sample Output

13 1
failed

___________________________________________________________________

Rezaul Alam Chowdhury 

“The easiest way to count cows in a grazing field is to count how many hooves are there and then divide it by four!”




#include <cstdio>
#include <cstdlib>
#include <cassert>
#include <algorithm>
#include <cmath>

/****************************************************************************
 *
 * let d = gcd (n1, n2)
 *     n1 * x + n2 * y = n  <==>  n1 / d * x + n2 / d * y = n / d  ... (1)
 * let n1 / d * x0 + n2 / d * y0 = 1  ... (2)
 *     x0 and y0 can be get by 'Extended Euclid Algorithm'.
 * multiply (2) by 'n / d' and compare to (1), we get:
 *     x = x0 * n / d
 *     y = y0 * n / d
 * if we have x, y such that:
 *     n1 * x + n2 * y = n
 * then we have:
 *     n1 * (x + i * n2 / d) + n2 * (y - i * n1 / d) = n   (i = 1, 2, ...)  ... (3)
 * because 'n1 * (x + i * n2 / d)' increase n1 * n2 / d while 'n2 * (y - i * n1 / d)' decrease n1 * n2 / d.
 * and here 'x' and 'y' are fixed values.
 *
 * according to the statement of the problem, x >= 0 and y >= 0.
 * so we get:
 *     x + i * n2 / d >= 0 and y - i * n1 / d >= 0
 * solve these two inequations we get the range of 'i', let's note the range [l, u]
 *
 * the problem asks us to minimize 'c1 * x + c2 * y',
 * let z = c1 * (x + i * n2 / d) + c2 * (y - i * n1 / d)  ... (4)
 * so (4) is what we want to minimize.
 * since it's monotonically either increasing or decreasing, what we need to do is examine two cases when i == l and i == u.
 *
 ****************************************************************************/

long long ExEuclid (long long a, long long b, long long &x, long long &y) {
    if (b == 0) {
        x = 1;
        y = 0;
        return a;
    }
    long long d = ExEuclid (b, a % b, y, x);
    y -= a / b * x;
    return d;
}

long long GCD (long long a, long long b) {
    if (b == 0) {
        return a;
    }
    return GCD (b, a % b);
}

int main () {
    long long n, c1, n1, c2, n2; // inputs of the problem
    while (scanf ("%lld%lld%lld%lld%lld", &n, &c1, &n1, &c2, &n2) == 5 && n) {
        long long d = GCD(n1, n2);
        if (n % d != 0) {
            printf ("failed\n");
            continue;
        }

        long long x0, y0;
        ExEuclid (n1 / d, n2 / d, x0, y0);

#ifdef _DEBUG
        printf ("d = %lld, n1 / d = %lld, n2 / d = %lld, x0 = %lld, y0 = %lld\n", d, n1 / d, n2 / d, x0, y0);
#endif

        /*
         * 1) x = n / d * x0 + i * n2 / d, and x >= 0
         * 2) y = n / d * y0 - i * n1 / d, and y >= 0
         * so, [lower, upper] is the range of 'i'.
         */
        long long lower = llrint (ceil (1.0 * -x0 * n / n2)); // lower of 'i'
        long long upper = llrint (floor (1.0 * y0 * n / n1)); // upper of 'i'
        if (lower > upper) {
            printf ("failed\n");
            continue;
        }

#ifdef _DEBUG
        printf ("lower = %lld, upper = %lld\n", lower, upper);
#endif

        long long xLower = n / d * x0 + lower * n2 / d;
        long long xUpper = n / d * x0 + upper * n2 / d; // by equation 1)

        long long yLower = n / d * y0 - lower * n1 / d;
        long long yUpper = n / d * y0 - upper * n1 / d; // by equation 2)

        long long vLower = c1 * xLower + c2 * yLower; // value of lower
        long long vUpper = c1 * xUpper + c2 * yUpper; // value of upper

#ifdef _DEBUG
        printf ("xLower = %lld, yLower = %lld, vLower = %lld\n", xLower, yLower, vLower);
        printf ("xUpper = %lld, yUpper = %lld, vUpper = %lld\n", xUpper, yUpper, vUpper);
#endif

        if (vLower < vUpper) {
#ifdef _DEBUG
            printf ("lower\n");
#endif
            printf ("%lld %lld\n", xLower, yLower);
        } else {
#ifdef _DEBUG
            printf ("upper\n");
#endif
            printf ("%lld %lld\n", xUpper, yUpper);
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值