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
",ansx,ansy);
	}
}

  

原文地址:https://www.cnblogs.com/jie-dcai/p/3955703.html