1. 农民分羊问题
问题描述: 农民有n个儿子,邻居有m头羊,农民怎么分羊?
(题设:儿子分配的多少与大小正比,允许几个儿子分到一样多的羊)
-
题分析和模型建立:
当 m = 1 时 , 解 决 原 题 其 实 是 求 解 1 x 1 + 1 x 2 + ⋯ + 1 x n + 1 = 1 的 不 定 方 程 的 所 有 可 能 解 这 是 个 不 定 方 程 的 的 问 题 , 利 用 递 归 便 可 以 解 决 当 m ! = 1 时 , 题 为 1 x 1 + 1 x 2 + ⋯ + m x n + 1 = 1 怎 么 把 这 里 化 为 第 一 种 的 形 式 呢 , 这 里 提 出 两 个 方 法 当m=1时,解决原题其实是求解\frac{1}{x_1}+\frac{1}{x_2}+\cdots+\frac{1}{x_{n+1}}=1的不定方程的所有可能解\\这是个不定方程的的问题,利用递归便可以解决\\当m!=1时,题为\frac{1}{x_1}+\frac{1}{x_2}+\cdots+\frac{m}{x_{n+1}}=1\\怎么把这里化为第一种的形式呢,这里提出两个方法 当m=1时,解决原题其实是求解x11+x21+⋯+xn+11=1的不定方程的所有可能解这是个不定方程的的问题,利用递归便可以解决当m!=1时,题为x11+x21+⋯+xn+1m=1怎么把这里化为第一种的形式呢,这里提出两个方法
-
将最后一项拆成m项
优点:较容易想到,直接在1题的代码上加判定就可
缺点:计算量较大(增加了m个迭代的维度,且判定会增加时间复杂度)
-
将原式变形
将 原 式 化 为 1 m ∗ x 1 + 1 m ∗ x 2 + ⋯ + 1 x n + 1 = 1 m 这 样 把 m ∗ x i 看 为 整 体 y i , 寻 找 m ∣ y i 的 即 可 计 算 量 并 不 明 显 增 加 , 且 依 然 化 为 了 跟 一 题 基 本 一 样 的 迭 代 将原式化为\frac{1}{m*x_1}+\frac{1}{m*x_2}+\cdots+\frac{1}{x_{n+1}}=\frac{1}{m}\\这样把m*x_i看为整体y_i,寻找m|yi的即可\\计算量并不明显增加,且依然化为了跟一题基本一样的迭代 将原式化为m∗x11+m∗x21+⋯+xn+11=m1这样把m∗xi看为整体yi,寻找m∣yi的即可计算量并不明显增加,且依然化为了跟一题基本一样的迭代
-
模型建立:
综上所述,模型即为求解 1 m ∗ x 1 + 1 m ∗ x 2 + ⋯ + 1 x n + 1 = 1 m \frac{1}{m*x_1}+\frac{1}{m*x_2}+\cdots+\frac{1}{x_{n+1}}=\frac{1}{m} m∗x11+m∗x21+⋯+xn+11=m1的满足条件的xi组数
接下来就是利用代码迭代实现。
-
-
流程图分析(解不定方程)
-
代码实现 (Java)
package homework; import java.util.Scanner; public class DivideSheep { static int[][] re = new int[10000][10]; \\如果n的个数增加,可能会增加10000(结果的个数) static int[] st = new int[10]; static int count = 0; static int num = 4,ne = 1;//儿子的个数和邻居的样数。默认为1 public static void divide(Fraction x, int a,int before) { // Fraction是现在剩余的分数,a是已分配的个数,before是上一个分数 // 其实before可以省略,因为等于re[count][a],但是为了简便; int tmp,tmp1; if(x.numerator == 0 && a == num) { for(int i=0;i<num;i++) re[count][i] = st[i]; count++; } if( a == num || x.numerator == 0) return; tmp = x.denominator / x.numerator ; tmp1 = x.denominator % x.numerator == 0 ? tmp : tmp+1; tmp1 = tmp1 > before ? tmp1 : before; for(int i=tmp1 ; i <= tmp*(num-a); i++) { if(i%ne != 0) continue; st[a] = i; divide(x.sub(new Fraction(1,i)),a+1,i); } return ; } public static void main(String args[]) { System.out.print("请输入儿子个数和邻居的羊数:\n"); Scanner in = new Scanner(System.in); num = in.nextInt()+1;ne = in.nextInt(); divide(new Fraction(1,1*ne),0,2); System.out.print("分配方法为:\n"); for(int i=0;i<count;i++) { for(int j=0;j<num-1;j++) System.out.print("第"+(j+1)+"个儿子分1/"+re[i][j]/ne+" "); System.out.print("农民有"+(re[i][num-1]-ne)+"条羊"); System.out.print("\n"); } in.close(); } }
-
样例截图
- n = 4, m = 1; n=3,m=2;
-
模型分析
在经过实验后,可以发现当n=5时,结果已经达到了千位的数量级,可想而知,儿子的个数越多,计算量越大,因此前面第一种算法的去电也就更明显,因为当n很大的时候,没加一个维数就会增加巨大的计算量,这也是我选择第二种算法的原因。
型分析
在经过实验后,可以发现当n=5时,结果已经达到了千位的数量级,可想而知,儿子的个数越多,计算量越大,因此前面第一种算法的去电也就更明显,因为当n很大的时候,没加一个维数就会增加巨大的计算量,这也是我选择第二种算法的原因。
而且,在计算机中,递归是一种非常耗时的数据结构,但普通不定方程的解法 就是与这种递归十分类似,所以可以知道,不定方程的普通解是非常耗时的,所以如果加上一些特殊条件会更好解决。