- /*
- 题目描述:
- 日本著名数学游戏专家中村义作教授提出这样一个问题:
- 父亲将k>0个桔子分给n个儿子
- 分完后父亲说:“
- 老1将分给你的桔子的1/p1给老二;
- 老2拿到后连同原先的桔子分1/p2给老三;
- ......(以此类推)
- 老n拿到后连同原先的桔子分1/pn给老大”。
- 结果大家手中的桔子正好一样多。问n兄弟原来手中各有多少桔子?
- 要求桔子数的和要最小
- 假如和最小仍然有多解,则输出老1手上最少的那个解
- 样例输入:
- 3
- 5 4 3
- 样例输出:
- 15 29 28
- 其它信息:
- 对于样例:
- 3
- 5 4 3
- 从初始状态15 29 28开始:
- 老1把手上的1/5给老2,结果变成
- 12 32 28
- 老2把手上的1/4给老3,结果变成
- 12 24 36
- 老3把手上的1/3给老1,结果变成
- 24 24 24
- 所以,15 29 28就是一组解
- */
- #include <stdio.h>
- #include <limits.h>
- int SolveOrange(unsigned long long n, unsigned long long *p, unsigned long long *solve);
- int main()
- {
- unsigned long long n = 3;
- unsigned long long p[3] = {5, 4, 3};
- unsigned long long result[3];
- if(SolveOrange(n , p, result)==0)
- {
- printf("%llu %llu %llu/n", result[0], result[1], result[2]);
- }
- else
- {
- printf("No Solve!/n");
- }
- return 0;
- }
- /*
- 输入参数: n 为儿子数目, p 为分配分母的数组, solve 是保存结果的数组。
- 输出参数: sovle 结果。
- 返回值:0 有结果;非零值无结果。
- 说明:p 和 solve 的长度必须与n相同。
- 无论有无结果,solve 中的值均会被破坏。
- */
- int SolveOrange(unsigned long long n, unsigned long long *p, unsigned long long *solve)
- {
- /* 这里插入参数合法性检查 */
- /* count 是最后每个人手中的桔子数目 */
- unsigned long long count;
- int i;
- /* 每次给出的桔子数目*/
- unsigned long long pass;
- /* 从 1 开始试,看看 count 最小是多少时,可以反推回第一次给出桔子前的状态 */
- /* 终值设为 ULLONG_MAX/n 以保证桔子总数不会超过 ULLONG_MAX,即大约 1.8e19 */
- for(count=1; count<=ULLONG_MAX/n; count++)
- {
- /* 最终所有人的手中都是 count 个桔子 */
- for(i=0; i<n; i++)
- solve[i] = count;
- /* 从最后一次给桔子开始反推 */
- for(i=n-1; i>=0; i--)
- {
- /* 第 i+1 次给出桔子后,第 i+1 个人手里的桔子数量应该能被 p[i]-1 整除 */
- if(solve[i]%(p[i]-1) != 0)
- break;
- /* 计算第 i+1 次给出的桔子数量 */
- pass = solve[i]/(p[i]-1);
- /* 第 i+1 次给出桔子后,第 i+2 个人手里的桔子数应该大于等于第 i+1 个人给他的数量 */
- if(solve[(i+1)%n]<pass)
- break;
- /* 嗯,符合条件,恢复第 i+1 次给出桔子之前的状态 */
- solve[(i+1)%n] -= pass;
- solve[i] += pass;
- }
- /* i 等于 -1 说明循环不是被break中断的, solve 已经是第一次给出桔子前的状态了 */
- if(i==-1)
- return 0;
- }
- /* 没有结果,不过我想程序一般不会跑到这里的, */
- /* 我大概算了一下,即使每一纳秒跑一次 count 循环,也要跑几十上百年 */
- return 1;
- }
分桔子问题
最新推荐文章于 2023-02-11 15:52:45 发布