1. 程式人生 > >倒酒(擴充套件歐幾里德)90分

倒酒(擴充套件歐幾里德)90分

題目描述

Winy是一家酒吧的老闆,他的酒吧提供兩種體積的啤酒,a ml和b ml,分別使用容積為a ml和b ml的酒杯來裝載。

酒吧的生意並不好。Winy發現酒鬼們都非常窮。有時,他們會因為負擔不起aml或者bml啤酒的消費,而不得不離去。因此,Winy決定出售第三種體積的啤酒(較小體積的啤酒)。

Winy只有兩種杯子,容積分別為a ml和b ml,而且啤酒杯是沒有刻度的。他只能通過兩種杯子和酒桶間的互相傾倒來得到新的體積的酒。

為了簡化倒酒的步驟,Winy規定:

(1)a≥b;

(2)酒桶容積無限大,酒桶中酒的體積也是無限大(但遠小於桶的容積);

(3)只包含三種可能的倒酒操作:

①將酒桶中的酒倒入容積為b ml的酒杯中;

②將容積為a ml的酒杯中的酒倒入酒桶;

③將容積為b ml的酒杯中的酒倒入容積為a ml的酒杯中。

(4)每次倒酒必須把杯子倒滿或把被傾倒的杯子倒空。

Winy希望通過若干次傾倒得到容積為a ml酒杯中剩下的酒的體積儘可能小,他請求你幫助他設計傾倒的方案

輸入輸出格式

輸入格式:

 

兩個整數a和b(0<b≤a≤10^9)

 

輸出格式:

 

第一行一個整數c,表示可以得到的酒的最小體積。

第二行兩個整數Pa和Pb(中間用一個空格分隔),分別表示從體積為a ml的酒杯中倒出酒的次數和將酒倒入體積為b ml的酒杯中的次數。

若有多種可能的Pa、Pb滿足要求,那麼請輸出Pa最小的一個。若在Pa最小的情況下,有多個Pb滿足要求,請輸出Pb最小的一個。

 

輸入輸出樣例

輸入樣例#1: 複製
5 3
輸出樣例#1: 複製
1
1 2

說明

樣例解釋:傾倒的方案為:

1、桶->B杯;2、B杯->A杯;

3、桶->B杯;4、B杯->A杯;

5、A杯->桶; 6、B杯->A杯;

 

思路:

    最開始是發現最小是gcd(a, b);然後,覺得pa, pb其實就是ax+by=gcd(a, b)其實a的x為負數相當於倒掉的意思。b的y為正數相當於裝滿。又因為,求y的最小正值,肯定是先減為負數,然後再加為最小正數。

#include<cstdio>
using namespace std;
#define ll long long
void exgcd(ll a, ll b, ll &d, ll &x, ll &y)
{
    if (b == 0){ d = a; x = 1; y = 0; }
    else { exgcd(b, a%b, d, y, x); y -= x*(a / b); }
}

int main(){
    ll a, b, d, x, y;
    scanf("%lld%lld", &a, &b);
    exgcd(a, b, d, x, y);
    while (y > 0){ x += b; y -= a; }
    while (y + a < 0){ x -= b; y += a; }
    x -= b; y += a;
    printf("%lld %lld\n", -x, y);
}