分桔子问题

来源:互联网 发布:良剑期乎断 不期乎镆铘 编辑:程序博客网 时间:2024/04/28 04:55
  1. /*
  2.     题目描述:
  3.     日本著名数学游戏专家中村义作教授提出这样一个问题:
  4.     父亲将k>0个桔子分给n个儿子
  5.     分完后父亲说:“
  6.     老1将分给你的桔子的1/p1给老二;
  7.     老2拿到后连同原先的桔子分1/p2给老三;
  8.     ......(以此类推)
  9.     老n拿到后连同原先的桔子分1/pn给老大”。
  10.     结果大家手中的桔子正好一样多。问n兄弟原来手中各有多少桔子?
  11.     要求桔子数的和要最小
  12.     假如和最小仍然有多解,则输出老1手上最少的那个解
  13.     样例输入:
  14.     3
  15.     5 4 3
  16.     样例输出:
  17.     15 29 28
  18.     其它信息:
  19.     对于样例:
  20.     3
  21.     5 4 3
  22.     从初始状态15 29 28开始:
  23.     老1把手上的1/5给老2,结果变成
  24.     12 32 28
  25.     老2把手上的1/4给老3,结果变成
  26.     12 24 36
  27.     老3把手上的1/3给老1,结果变成
  28.     24 24 24
  29.     所以,15 29 28就是一组解 
  30. */
  31. #include <stdio.h>
  32. #include <limits.h>
  33. int SolveOrange(unsigned long long n, unsigned long long *p, unsigned long long *solve);
  34. int main()
  35. {
  36.     unsigned long long n = 3;
  37.     unsigned long long p[3] = {5, 4, 3};
  38.     unsigned long long result[3];
  39.     if(SolveOrange(n , p, result)==0)
  40.     {
  41.         printf("%llu %llu %llu/n", result[0], result[1], result[2]); 
  42.     }
  43.     else
  44.     {
  45.         printf("No Solve!/n");
  46.     }
  47.     return 0;
  48. }
  49. /*
  50.     输入参数: n 为儿子数目, p 为分配分母的数组, solve 是保存结果的数组。
  51.     输出参数: sovle 结果。
  52.     返回值:0 有结果;非零值无结果。
  53.     说明:p 和 solve 的长度必须与n相同。
  54.           无论有无结果,solve 中的值均会被破坏。
  55. */
  56. int SolveOrange(unsigned long long n, unsigned long long *p, unsigned long long *solve)
  57. {
  58.     /*  这里插入参数合法性检查  */
  59.     
  60.     /*  count 是最后每个人手中的桔子数目  */
  61.     unsigned long long count;
  62.     int i;
  63.     /*  每次给出的桔子数目*/
  64.     unsigned long long pass;
  65.     
  66.     /*  从 1 开始试,看看 count 最小是多少时,可以反推回第一次给出桔子前的状态  */
  67.     /*  终值设为 ULLONG_MAX/n 以保证桔子总数不会超过 ULLONG_MAX,即大约 1.8e19  */
  68.     for(count=1; count<=ULLONG_MAX/n; count++)
  69.     {
  70.         /*  最终所有人的手中都是 count 个桔子  */
  71.         for(i=0; i<n; i++)
  72.             solve[i] = count;
  73.         
  74.         /*  从最后一次给桔子开始反推  */
  75.         for(i=n-1; i>=0; i--)
  76.         {
  77.             /*  第 i+1 次给出桔子后,第 i+1 个人手里的桔子数量应该能被 p[i]-1 整除  */
  78.             if(solve[i]%(p[i]-1) != 0)
  79.                 break;
  80.             /*  计算第 i+1 次给出的桔子数量  */
  81.             pass = solve[i]/(p[i]-1);
  82.             /*  第 i+1 次给出桔子后,第 i+2 个人手里的桔子数应该大于等于第 i+1 个人给他的数量  */
  83.             if(solve[(i+1)%n]<pass)
  84.                 break;
  85.             /*  嗯,符合条件,恢复第 i+1 次给出桔子之前的状态  */
  86.             solve[(i+1)%n] -= pass;
  87.             solve[i] += pass;
  88.         }
  89.         /*  i 等于 -1 说明循环不是被break中断的, solve 已经是第一次给出桔子前的状态了  */
  90.         if(i==-1)
  91.             return 0;
  92.     }
  93.     /*  没有结果,不过我想程序一般不会跑到这里的,  */
  94.     /*  我大概算了一下,即使每一纳秒跑一次 count 循环,也要跑几十上百年  */
  95.     return 1;
  96. }
原创粉丝点击