倒酒(擴充套件歐幾里德)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); }