SOL : 扩展的欧几里德, ax+by==c
x=x0+b/d*t;
y=y0-a/d*t;
求|x|+|Y|的最小值
可以发现:
|x0+b/d*t| 单调递增 |y0-a/d*t| 单调递减
因为 a>b,所以就是说函数是凹的,先减小后增大。
显然 当y0-a/d*t==0的时候 |x|+|Y| 最小值就在那附近。
枚举几个值就能找到。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
inline int exgcd(int a,int b,int &x,int &y)
{
if(b==0)
{
x=1;
y=0;
return a;
}
int d=exgcd(b,a%b,x,y);
int t=x;
x=y;
y=t-(a/b)*y;
return d;
}
int main()
{
int a,b,c,x,y,d,x1,y1,ansx,ansy;
bool flag;
while(~scanf("%d%d%d",&a,&b,&c),a+b+c)
{
flag=false;
if(a<b)
{
flag=true;
swap(a,b);
}
d=exgcd(a,b,x,y);
x*=(c/d);
y*=(c/d);
int t=y*d/a;
ansx=abs(x+t*b/d);
ansy=abs(y-t*a/d);
for(int i=1;i<5;i++)
{
x1=x+(t+i)*b/d;
y1=y-(t+i)*a/d;
x1=abs(x1);
y1=abs(y1);
if(x1+y1<ansx+ansy||(x1+y1==ansx+ansy&&x1*a+y1*b<ansx*a+ansy*b))
{
ansx=x1;
ansy=y1;
}
x1=x+(t-i)*b/d;
y1=y-(t-i)*a/d;
x1=abs(x1);
y1=abs(y1);
if(x1+y1<ansx+ansy||(x1+y1==ansx+ansy&&x1*a+y1*b<ansx*a+ansy*b))
{
ansx=x1;
ansy=y1;
}
}
if(flag)
swap(ansx,ansy);
printf("%d %d\n",ansx,ansy);
}
return 0;
}