zoukankan      html  css  js  c++  java
  • POJ 2142 The Balance ★ (不定方程 ax+by=c 的|x|+|y|最小解)

    题目大意:给定两个重a,b的砝码来称一个d重的东西,求出a,b所需的数量x,y要求x+y最小,当相等时ax+by最小. 题目链接http://poj.org/problem?id=2142   显然就是解方程ax + by = d ,当x,y都>0时在一侧,异号时便异侧. 那么剩下的问题就是如何寻找|x|+|y|的最小解了.   我们来看方程的通解: x = x0 + kb y = y0 - ka   如果我们对函数方程还熟悉的话就会发现这是一条平面直角坐标系内的直线: 未命名     于是我们可发现|x|+|y|最小值一定在坐标轴附近的整点(枚举一下坐标轴附近的正点和负点比较一下就行了……),至于是x轴还是y轴要看a大还是b大.  
    #include 
    #include 
    using namespace std;
    int abs(int a){
        return a>0?a:-a;
    }
    int gcd(int a, int b){
        return b?gcd(b, a%b):a;
    }
    void ext_gcd(int a, int b, int &x, int &y){
        if (b == 0){
            x = 1;
            y = 0;
            return ;
        }
        ext_gcd(b, a%b, x, y);
        int tmp = x;
        x = y;
        y = tmp - a/b*y;
        return ;
    }
    void fuck(int a, int b, int c, int &minx, int &miny){
        int g = gcd(a,b);
        a /= g;
        b /= g;
        c /= g;
        int x0, y0;
        ext_gcd(a, b, x0, y0);
        x0 *= c;
        y0 *= c;
    
        miny = minx = (1 << 25);
        if (a < b){
            int tmp_x = (x0%b+b) % b;
            int k = (tmp_x - x0) / b;
            x0 = tmp_x;
            y0 = y0 - k*a;
            for (int p = 0; p >= -1; p --){
                x0 = x0 + p*b;
                y0 = y0 - p*a;
                if (abs(x0)+ abs(y0) < minx + miny){
                    minx = abs(x0);
                    miny = abs(y0);
                }
                else if (abs(x0)+ abs(y0) == minx + miny)
                    if (abs(x0)*a + abs(y0)*b < minx*a + miny*b){
                        minx = abs(x0);
                        miny = abs(y0);
                    }
            }
        }
        else{
            int tmp_y = (y0%a+a) % a;
            int k = (tmp_y - y0) / a;
            y0 = tmp_y;
            x0 = x0 - k*b;
            for (int p = 0; p <= 1; p ++){
                x0 = x0 + p*b;
                y0 = y0 - p*a;
                if (abs(x0)+ abs(y0) < minx + miny){
                    minx = abs(x0);
                    miny = abs(y0);
                }
                else if (abs(x0)+ abs(y0) == minx + miny)
                    if (abs(x0)*a + abs(y0)*b < minx*a + miny*b){
                        minx = abs(x0);
                        miny = abs(y0);
                    }
            }
        }
    
    }
    int main(){
        int a, b, d;
        while(scanf("%d%d%d", &a, &b, &d) == 3){
            if (a + b + d == 0)
                break;
            int minx, miny;
            fuck(a, b, d, minx, miny);
            printf("%d %d\n", minx, miny);
        }
        return 0;
    }
    
     
    举杯独醉,饮罢飞雪,茫然又一年岁。 ------AbandonZHANG
  • 相关阅读:
    android学习日记08--Paint画笔
    android学习日记07--Canvas画布
    android学习日记06--SurfaceView视图
    android学习日记06--View视图
    android学习日记05--Activity间的跳转Intent实现
    android学习日记04--开发中的通用细节
    android学习日记03--常用控件Dialog
    android学习日记03--常用控件ListView
    android学习日记03--常用控件tabSpec/tabHost
    android学习日记03--常用控件progressbar/seekbar
  • 原文地址:https://www.cnblogs.com/AbandonZHANG/p/4114208.html
Copyright © 2011-2022 走看看