POJ 2142
这道题的难点在于求|x|+|y|的为最小的值吧。想了好久才想出来,发现自己的数学能力确实跟不上。
可知。x=x0+b/d*t;y=y0-a/d*t;则为
|x0+b/d*t|+|y0-a/d*t|,仔细想想,可以看成的是两条直线方程y绝对值之和。
那么,必然最小值只能出现在两条直线方程的两个零点之间,则枚举两个零点之间的值赋于t即可解。
#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
int gcd(int a,int b){
if(b==0) return a;
return gcd(b,a%b);
}
void exgcd(int a,int b ,int &x,int &y){
if(b==0){
x=1;y=0; return;
}
exgcd(b,a%b,x,y);
int t=x;
x=y;
y=t-a/b*y;
}
int main(){
int a,b,c,x0,y0;
while(scanf("%d%d%d",&a,&b,&c),a||b||c){
int g=gcd(a,b);
a/=g; b/=g; c/=g;
exgcd(a,b,x0,y0);
x0*=c; y0*=c;
int minc=(1<<31)-1,summ=(1<<31)-1;
int l=-(x0)/b,r=(y0)/a;
if(l>r){
int tmp=l;
l=r;
r=tmp;
}
// cout<<"x0="<<x0<<' '<<"y0="<<y0<<endl;
// cout<<"a="<<a<<' '<<"b="<<b<<endl;
// cout<<l<<' '<<r<<endl;
int ansx,ansy;
for(int i=l-10;i<=r+10;i++){
if(abs(x0+b*i)+abs(y0-a*i)<minc){
minc=abs(x0+b*i)+abs(y0-a*i);
summ=g*a*abs(x0+b*i)+g*b*abs(y0-a*i);
ansx=abs(x0+b*i); ansy=abs(y0-a*i);
}
else if(abs(x0+b*i)+abs(y0-a*i)==minc){
if(g*a*abs(x0+b*i)+g*b*abs(y0-a*i)<summ){
summ=g*a*abs(x0+b*i)+g*b*abs(y0-a*i);
ansx=abs(x0+b*i); ansy=abs(y0-a*i);
}
}
}
printf("%d %d\n",ansx,ansy);
}
}

浙公网安备 33010602011771号