java实现 ----电容充电

有一台用电容组成的计算器,其中每个电容组件都有一个最大容量值(正整数)。
对于单个电容,有如下操作指令:
指令1:放电操作——把该电容当前电量值清零
指令2:充电操作——把该电容当前电量补充到其最大容量值
对于两个电容A和B,有如下操作指令:
指令3:转移操作——从A中尽可能多的将电量转移到B,转移不会有电量损失,如果能够充满B的最大容量,那剩余的电量仍然会留在A中

现在已知有两个电容,其最大容量分别为a和b其初始状态都是电量值为0,希望通过一系列的操作可以使其中某个电容(无所谓哪一个)中的电量值等于c(c也是正整数),这一系列操作所用的最少指令条数记为M,如果无论如何操作,都不可能完成,则定义此时M=0。
显然对于每一组确定的a、b、c,一定会有一个M与其对应。

输入描述:
每组测试样本的输入格式为:
第一行是一个正整数N
从第二行开始,每行都是3个正整数依次组成一组a、b、c,一共有N组
输出描述:
输出为N行,每行打印每一组对应的M
备注:
数据范围:

N:0<N<100 
a、b、c: 
0<a、b、c<10^550%) 
0<a、b、c<10^730%) 
0<a、b、c<10^920%) 

输入
2
3 4 2
2 3 4
4
0
对于(3,4,2),最少只需要4个指令即可完成:
(设最大容量为3的是A号电容,另一个是B号电容)
1. 充电A
2. 转移A->B
3. 充电A
4. 转移A->B
此时A中当前电量为2,操作完成,所以输出4。
对于(2,3,4),显然不可能完成,输出0。

import java.util.Scanner;

/**
 * 分析请看参考网址:  
 *  https://blog.csdn.net/u014251675/article/details/81572135
 *
 * @author Liu
 * @date 2018-08-16 11:51
 */
public class DiaoRongChongDian {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int N = sc.nextInt();
        long[] A = new long[N];
        long[] B = new long[N];
        long[] C = new long[N];
        // 输入数据
        for (int i = 0; i < N; i++) {
            A[i] = sc.nextLong();
            B[i] = sc.nextLong();
            C[i] = sc.nextLong();
        }
        // 开始处理数据
        for (int i = 0; i < N; i++){
            long a = A[i];
            long b = B[i];
            long c = C[i];
            long[] d = ex_gcd(a, b);
            // 如果c 大于 a和b 亦或是c%d不为0,则代表不可能实现
            if (c>a&&c>b||c%d[0]!=0){
                System.out.println(0);
                continue;
            }else if (a==c||b==c){//c 恰巧为b或者a,一次就够了
                System.out.println(1);
                continue;
            }else {
                long x = d[1];
                long y = d[2];
                if (d[2]>0){
                    long temp2 = x;
                    x = y;
                    y = temp2;
                    long temp = a;
                    a = b;
                    b = temp;
                }
                // 使ax + by = c (d是c的因子,即对上面式子ax + by = d两边同时乘以c / d)
                long a2 = a/d[0];
                long b2 = b/d[0];
                x *= c/d[0];
                y *= c/d[0];

                /* 最小化|x|+|y|
                *  ax+by=c的全部整数解为:
                *           x+kb/gcd(a,b)
                *           y−ka/gcd(a,b),      k=...,−2,−1,0,1,2,...
                * */

                long k = x/b2;
                x -= k*b2;// 使这组(x, y)最接近0(x > 0时的整数解)
                y += k*a2;
                long res ;
                if (c>a){
                    res = 2*(x-y);
                }else {
                    res = 2*(x-y-1);
                }
                x -= b2;// 使这组(x, y)最接近0(y > 0时的整数解)
                y += a2;
                if (c>b){
                    res = Math.min(res,2*(y-x)); // 上文分析中假设x > 0,这里y > 0
                }else {
                    res = Math.min(res,2*(y-x-1));
                }
                System.out.println(res);
            }

        }

        sc.close();

    }
    /**
     * 扩展欧里几何
     * 存在整数对 x,y ,使得 gcd(a,b)=ax+by
     *
     * @param a
     * @param b
     * @return 第一个值是最大公约数,第二个值表示C++语言实现中的x,第三个值表示y。
     */
    public static long[] ex_gcd(long a, long b) {
        long ans;
        long[] result = new long[3];
        if (b == 0) {
            result[0] = a;
            result[1] = 1;//x
            result[2] = 0;//y
            return result;
        }
        long[] temp = ex_gcd(b, a % b);
        ans = temp[0];//ans 相当于t
        result[0] = ans;
        result[1] = temp[2];
        result[2] = temp[1] - (a / b) * temp[2];
        return result;
    }
    //普通的最大公约数的求法
    public static long common_gcd(long a, long b) {
        return a % b == 0 ? b : common_gcd(b, a % b);
    }
}

引用https://blog.csdn.net/u014251675/article/details/81572135块内容

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值