• 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
  • 相关阅读:
    JZOJ6096 森林
    HIT暑期集训 二分图匹配
    HIT暑期集训 网络流
    HIT暑期集训 tarjan,dfs序
    HIT暑期集训 图论基础
    HIT暑期集训 AC自动机
    HIT第二周 周测补题
    HIT暑期集训 字符串
    HIT暑期集训 动态规划
    HIT暑期集训 平衡树
  • 原文地址:https://www.cnblogs.com/AbandonZHANG/p/4113990.html
Copyright © 2020-2023  润新知