poj2142_The Balance

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define INF 0x3f3f3f3f
#define rep0(i, n) for (int i = 0; i < n; i++)
#define rep1(i, n) for (int i = 1; i <= n; i++)
#define rep_0(i, n) for (int i = n - 1; i >= 0; i--)
#define rep_1(i, n) for (int i = n; i > 0; i--)
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
#define mem(x, y) memset(x, y, sizeof(x))
/**
题目大意
用a, b两种砝码称出d
答案先最小化x + y 
后最小化a * x + b * y

思路
分两种
1. 
a * x + b * y = d
x = (d - b * y) / a
x + y = (1 - b / a) * y + d / a
if b >= a
    最大化y (保证y <= d / b)
else
    最小化y

2.
a * x - b * y = d
<=>
a * x + b * (-y) = d
设y' = -y
x + y = (b / a + 1) * y + d / a
so 最小化y
扩展欧几里得求y'的通解y"
通过y"求绝对值最小的负的特解
s = a / gcd(a, b)
y = -(y" % s - s) % s

同理考虑 b * y - a * y = d

HINT
在情况1和情况2 x + y 相等时 情况1的 a * x + b * y 更小

*/

using namespace std;
int exgcd(int a, int b, int &x, int &y)
{
    if (b == 0)
    {
        x = 1;
        y = 0;
        return a;
    }
    int r = exgcd(b, a % b, x, y);
    int temp = x;
    x = y;
    y = temp - a / b * y;
    return r;
}


int main()
{
    #ifndef ONLINE_JUDGE
        freopen("in.txt", "r", stdin);
    #endif // ONLINE_JUDGE
    int a, b, d, x, y, x1, y1, temp1, temp2;
    while (scanf("%d %d %d", &a, &b, &d) != EOF && a)
    {
        int g = exgcd(a, b, temp1, temp2);
        int s = a / g;
        temp2 *= d / g;

        y = -(temp2 % s - s) % s;
        x = (d + b * y) / a;
       
        if (b <= a)
        {

            y1 = (temp2 % s + s) % s;
            x1 = (d - b * y1) / a;
            if (x1 >= 0 && x1 + y1 <= x + y)
            {
                x = x1;
                y = y1;
            }

        }

        if (b > a)
        {
            temp2 = (temp2 % s + s) % s;
            while (temp2 + s <= d / b)
            {
                temp2 += s;
            }
            temp1 = (d - b * temp2) / a;
            if (temp2 <= d / b && temp1 + temp2 <= x + y)
            {
                x = temp1;
                y = temp2;
            }
        }
        g = exgcd(b, a, temp2, temp1);
        s = b / g;
        temp1 *= d / g;
        temp1 = -(temp1 % s - s) % s;
        temp2 = (d + a * temp1) / b;
        if (temp1 + temp2 < x + y)
        {
            x = temp1;
            y = temp2;
        }
        printf("%d %d\n", x, y);



    }

    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值