有一台用电容组成的计算器,其中每个电容组件都有一个最大容量值(正整数)。
对于单个电容,有如下操作指令:
指令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^5(50%)
0<a、b、c<10^7(30%)
0<a、b、c<10^9(20%)
输入
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块内容