POJ2142-The Balance(拓展欧几里得+个人小结)

9 篇文章 0 订阅
1 篇文章 0 订阅

The Balance
Time Limit: 5000MS Memory Limit: 65536K
Total Submissions: 7661 Accepted: 3368
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
题目:POJ2142
题意:给你两种规格的的砝码,和一件物品,要求你选出最小的砝码个数用天平称出这件物品。如果存在两种个数相同的情况,选择砝码总重量较少的。
思路:设给出的砝码规格和物品重量为a,b,c。
那么使天平平衡的条件应该是:ax=c+by(x为a砝码的个数,y为b砝码的个数)。
我们对原式移项得:ax+b(-y)=c
好,我们现在先来看一下拓展欧几里得算法。
拓展欧几里得算法只有一个功能,即求方程:ax0+by0=gcd(a,b)的解
很明显上述方程有多组解,其通解可表示为:
X=X0+b/gcd(a,b)
Y=Y0-a/gcd(a,b)
我们都知道欧几里得算法:gcd(x,y)=gcd(y,x%y),C++代码形如:
这里写图片描述
那么我们能否用这个算法求出X0和Y0呢?我们先写出关系式:
gcd(a,b)=gcd(b,a%b)
aX0+bY0=gcd(a,b)
bX1+(a%b)Y1=gcd(b,a%b)
我们知道:a%b=a-a/b*b,把几个式子合并一下:
aX0+bY0=gcd(a,b)
aY1+b(X1-a/b*Y1)=gcd(b,a%b)
对比一下,是否发现了什么?没错
X0=Y1
Y0=X1-a/b*Y1
这样,我们就可以用欧几里得算法算出X0和Y0了,代码实现如下:
这里写图片描述
对于本题:我们的任务时求出|x|+|y|的最小值,我们写出|x|,|y|的表达式:
|x|=|X0+b/gcd(a,b)*t| 单调递增
|y|=|Y0-a/gcd(a,b)*t| 单调递减
如果我们规定a>b,可以发现:|x|+|y|=|X0+b/gcd(a,b)*t|+|Y0-a/gcd(a,b)*t|
由于a< b,|Y0-a/gcd(a,b)*t|的斜率更大,所以当|Y0-a/gcd(a,b)*t|==0时,方程取得最小值。我们只需枚举|Y0-a/gcd(a,b)*t|趋近于0时左右两个t值,即可求得答案。
AC代码如下:

#include<stdio.h>
#include<math.h>
#include<string.h>
#include<algorithm>
#include<queue>
#include<vector>
#define met(s,k) memset(s,k,sizeof s)
#define scan(a) scanf("%d",&a)
#define scanl(a) scanf("%lld",&a)
#define scann(a,b) scanf("%d%d",&a,&b)
#define scannl(a,b) scanf("%lld%lld",&a,&b)
#define scannn(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define prin(a) printf("%d\n",a)
#define prinl(a) printf("%lld\n",a)
using namespace std;
typedef long long ll;
const int maxn=1e6+10;
const int inf=2100;
const double eps=1e-4;
int exgcd(int a,int b,int &x,int &y)
{
    if(b==0)
    {
        x=1;
        y=0;
        return a;
    }
    int ans=exgcd(b,a%b,x,y);
    int temp=x;
    x=y;
    y=temp-a/b*y;
    return ans;
}
int main()
{
    int a,b,c,x,y,t,x1,y1,x2,y2,ex,ey;
    while(scannn(a,b,c),a|b|c)
    {
        t=0;
        int change=0;
        if(a<b)
        {
            swap(a,b);
            change=1;
        }
        int gcd=exgcd(a,b,x,y);
        a/=gcd,b/=gcd,c/=gcd;
        x*=c,y*=c;
        if(y>0)
        {
            while(y-a*t>0)t++;
            x1=abs(x+b*t);
            y1=abs(y-a*t);
            t--;
            x2=abs(x+b*t);
            y2=abs(y-a*t);
        }
        else
        {
            while(y-a*t<0)t--;
            x1=abs(x+b*t);
            y1=abs(y-a*t);
            t++;
            x2=abs(x+b*t);
            y2=abs(y-a*t);
        }
        if(x1+y1<x2+y2||((x1+y1==x2+y2)&&(x1*a+y1*b<x2*a+y2*b)))ex=x1,ey=y1;
        else ex=x2,ey=y2;
        if(change)printf("%d %d\n",ey,ex);
        else printf("%d %d\n",ex,ey);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值