poj - 2142 超详细解释 数论【扩展欧几里得】

扩展欧几里得

题目链接:The Balance
题目描述:
Description

Ms. Iyo Kiffa-Australis has a balance and only two kinds of weights to measure a dose of medicine. For example, to measure 200mg of aspirin using 300mg weights and 700mg weights, she can put one 700mg weight on the side of the medicine and three 300mg weights on the opposite side (Figure 1). Although she could put four 300mg weights on the medicine side and two 700mg weights on the other (Figure 2), she would not choose this solution because it is less convenient to use more weights.
You are asked to help her by calculating how many weights are required.

Input

The input is a sequence of datasets. A dataset is a line containing three positive integers a, b, and d separated by a space. The following relations hold: a != b, a <= 10000, b <= 10000, and d <= 50000. You may assume that it is possible to measure d mg using a combination of a mg and b mg weights. In other words, you need not consider “no solution” cases.
The end of the input is indicated by a line containing three zeros separated by a space. It is not a dataset.
Output

The output should be composed of lines, each corresponding to an input dataset (a, b, d). An output line should contain two nonnegative integers x and y separated by a space. They should satisfy the following three conditions.
You can measure dmg using x many amg weights and y many bmg weights.
The total number of weights (x + y) is the smallest among those pairs of nonnegative integers satisfying the previous condition.
The total mass of weights (ax + by) is the smallest among those pairs of nonnegative integers satisfying the previous two conditions.

No extra characters (e.g. extra spaces) should appear in the output.
Sample Input

700 300 200
500 200 300
500 200 500
275 110 330
275 110 385
648 375 4002
3 1 10000
0 0 0
Sample Output

1 3
1 1
1 0
0 3
1 1
49 74
3333 1

题目大意:
输入三个数,a,b,d。a和b分别代表两种砝码,d代表要称的重量。题意就是用x个a砝码和y个b砝码称出d重量,砝码可以都放在一边,也可以放在两边,但是放两边的砝码的每一边必须是同种砝码,求最小的x,y并使得x+y最小。于是问题就转换成了求解ax+by=d这个方程。扩展欧几里得就是专门解决这类问题的,扩展欧几里得就是求解ax+by=gcd(a,b)得。所以若d是a,b最大公约数的倍数,那么该定理成立。
解题思路:
首先,肯定是先套扩展欧几里得模板,exgcd(a,b,x,y)。

int exgcd(int a,int b,int &x,int &y){
	if(b==0){
		x=1;
		y=0;
		return a;
	}
	int q=exgcd(b,a%b,x,y);
	int t=x;
	x=y;
	y=t-a/b*y;
	return q;
}

对于返回值,就是最大公约数,只不过同时我们还求出了ax+by=gcd(a,b)的解x,y。接下来我们再乘d/gcd(a,b),就可以得到原方程的一个解。设gcd(a,b)为md。
则另d/=md,就得到一个倍数关系,故此时xd和yd就是原方程的解(ax+by=d)。

这里再介绍一下欧几里得求解方程后的通解:我们的得到一个特解x0,y0。若设md=gcd(a,b),则x=x0+bt/md,y=y0-at/md。这里的t为任意常数。

再继续回到本题,由于他要找最小正整数解,所以我们有两种情况,另x为最小正解,再回代求y,然后要对y取绝对值!因为我们如果两种砝码放在两边,方程中间其实是用减号连接的,所以求出的x,y理应都大于等于0。同理,先求y也有一组最小解,最后我们再比较他们的大小,以求出x+y的最小值。接下来我给出一张图解,表示对第一种情况下对x的求解,其实就是代码的解释,方便大家看懂。

我觉得很形象了。。
最后,给出代码吧,大家结合我上面的解释一起看,很容易懂得,嘻嘻~

代码展示:

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string>
#include<cstring>
#include<cmath>
#include<stack>
using namespace std;
#define N 100001
#define maxn 1005
typedef long long ll;
int exgcd(int a,int b,int &x,int &y){
	if(b==0){
		x=1;
		y=0;
		return a;
	}
	int q=exgcd(b,a%b,x,y);
	int t=x;
	x=y;
	y=t-a/b*y;
	return q;
}
int main(){
	int a,b,d,p,q,x,y;
	while(~scanf("%d%d%d",&a,&b,&d)){
		if(a==0&&b==0&&d==0) return 0;
		int md=exgcd(a,b,x,y);
		a/=md,b/=md,d/=md;
		int x1=x*d;
		x1=(x1%b+b)%b;
		int y1=(d-a*x1)/b;
		y1=abs(y1);
		int y2=y*d;
		y2=(y2%a+a)%a;
		int x2=(d-b*y2)/a;
		x2=abs(x2);
		if(x1+y1<x2+y2) printf("%d %d\n",x1,y1);
		else printf("%d %d\n",x2,y2);
	}
	return 0;
}
发布了43 篇原创文章 · 获赞 56 · 访问量 5131

猜你喜欢

转载自blog.csdn.net/tran_sient/article/details/96432444