【题目】
有一群海盗(不多于20人),在船上比拼酒量。过程如下:打开一瓶酒,所有在场的人平分喝下,有几个人倒下了。再打开一瓶酒平分,又有倒下的,再次重复...... 直到开了第4瓶酒,坐着的已经所剩无几,海盗船长也在其中。当第4瓶酒平分喝下后,大家都倒下了。等船长醒来,发现海盗船搁浅了。他在航海日志中写到:“......昨天,我正好喝了一瓶.......奉劝大家,开船不喝酒,喝酒别开船......”
请你根据这些信息,推断开始有多少人,每一轮喝下来还剩多少人。
如果有多个可能的答案,请列出所有答案,每个答案占一行。
格式是:人数,人数,...
例如,有一种可能是:20,5,4,2,0。
【分析】
根据题目描述,船长每次都参与了喝酒,并且船长喝了4次总共喝了1瓶酒;
可以分析出题目的需求是要找到4个分数之和等于1,并且这4个分数的分子都是1,需要我们通过编程找到分母。
【源码】
我们需要一个有理数类,这个类包括一个分子和一个分母两个属性,代码如下:
public class Rational {
private int fz; // 分子
private int fm; // 分母
public Rational(int fz, int fm) {
int gcd = gcd(fz, fm); // 获取到fz和fm的最大公约数
this.fz = fz / gcd; // 对分子进行约分
this.fm = fm / gcd; // 对分母进行约分
}
// 当前分数与其他分数进行加法运算
// 原理:a/b + c/d = (ad+bc)/bd
public Rational add(Rational n) {
Rational ret = new Rational(
(this.fz * n.getFm() + this.fm * n.getFz()), this.fm
* n.getFm());
return ret;
}
public int getFz() {
return fz;
}
public void setFz(int fz) {
this.fz = fz;
}
public int getFm() {
return fm;
}
public void setFm(int fm) {
this.fm = fm;
}
/**
* 利用辗转相除法计算两个数x和y的最大公约数
*
* @param x
* @param y
* @return 返回x和y的最大公约数
*/
private int gcd(int x, int y) {
if (y == 0) {
return x;
} else {
return gcd(y, x % y);
}
}
}
接下来我们就可以开始通过4层for循环来遍历搜寻我们需要找到的答案,代码如下:
public class Test001 {
public static void main(String[] args) {
for (int i = 20; i > 0; i--) {
for (int j = i - 1; j > 0; j--) {
for (int p = j - 1; p > 0; p--) {
for (int q = p - 1; q > 0; q--) {
Rational a = new Rational(1, i);
Rational b = new Rational(1, j);
Rational c = new Rational(1, p);
Rational d = new Rational(1, q);
Rational ret = a.add(b).add(c).add(d);
if (ret.getFz() == 1 && ret.getFm() == 1) {
// 找到了一组答案
System.out.println(i + "," + j + "," + p + "," + q
+ ",0");
}
}
}
}
}
}
}
【结果】