二元不定方程

poj  2142

http://hi.baidu.com/5l2_/blog/item/a0381951b5738a1e367abef0.html 这个文章写的很好。。。按照这位大牛写的。。

大概意思 给定 a b k找到满足ax+by=k 的令|x|+|y|最小(等时令a|x|+b|y|最小)不妨a 〉b


先用扩展欧几里得算法求出 一组解 x0,y0,通解可以表示为x=x0+b/d *t y=y0-a/d *t


|x|+|y|=|x0+b/d *t |+|y0-a/d *t| 这个关于t的函数的最小值应该在t零点附近(因为要求t为整数)取到,再进一步考虑知道在   y0*d/a 附近的两整点里取。故直接验证这两点即可


因为   设a>b之后


|x0+b/d *t| 单调递增,|y0-a/d*t| 先递减再递增。因斜率a/d>b/d,所以总的|x0+b/d *t |+|y0-a/d *t| 先递减再递增,使y0-a/d*t0=0 的t0附近有最小值。

关于ax + by = d  通解可以表示为x=x0+b/d *t y=y0-a/d *t   因为:

任意的k a*x0+b*y0=k 对于任一解 如果 ax+by=k=ax0+by0 得 a(x-x0)=b(y0-y), d=gcd(a,b) gcd(a/d,b/d)=1 又 (a/d)*(x-x0)=(b/d)(y0-y) 那么 b/d|x-x0 设 x-x0=t*b/d 代入的 y0-y=t*a/d 这样就可得出通解形式 x=x0+b/d *t, y=y0-a/d *t 。。。。

代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
using namespace std;
int x,y,a1,b1;
int ex_gcd(int a,int b,int &x,int &y)
{
    if(b==0)
    {
        x=1;y=0;
        return a;
    }
    int d=ex_gcd(b,a%b,x,y);
    int x1=y;
    int y1=x-a/b*y;
    x=x1;
    y=y1;
    return d;
}
int cx(int t)
{
    return abs(x+a1*t);
}
int cy(int t)
{
    return abs(y-b1*t);
}
int main()
{
    int a,b,d,k;bool flag;
    int x1,x2,y1,y2,r,ax,ay,r1,r2;
    while(scanf("%d%d%d",&a,&b,&k)!=EOF)
    {
        if(a==0&&b==0&&k==0)
        break;
        flag=1;
       if(a<b)
       {
           flag=0;swap(a,b);
       }
       d=ex_gcd(a,b,x,y);
       x=x*(k/d);y=y*(k/d);
       a1=b/d;b1=a/d;r1=y/b1;
       if(y-b1*r1<=0)
       r1--;
       r2=r1+1;
       x1=cx(r1);y1=cy(r1);
       x2=cx(r2);y2=cy(r2);
       if(x1+y1<x2+y2)r=r1;
       else
       if(x1+y1>x2+y2)r=r2;
       else
       {
         if(a*x1+b*y1<a*x2+b*y2)
         r=r1;
         else
         r=r2;
       }
       ax=cx(r);ay=cy(r);
       if(flag)
       printf("%d %d\n",ax,ay);
       else
       printf("%d %d\n",ay,ax);
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值