泊松分酒
2017-01-01 07:28
169 查看
泊松分酒是一个著名的智力测试题,也是一个有难度的过程模拟经典案例;
1.案例提出:
法国数学家泊松(Poisson)曾提出以下分酒趣题:
某人有一瓶12品脱(容量单位)的酒,同时有容积为5品脱与8品脱的空杯各一个,借助这两个空杯,如何将这瓶12品脱的酒平分?
我们要解决一般的平分酒案例:
借助容量分别为bv与cv(单位为整数)的两个空杯,用最少的分倒次数把总容量为偶数a的酒平分,这里正整数bv、cv与偶数a均从键盘输入;
2.模拟设计:
求解一般的“泊松分酒”问题:借助容积分别为整数bv、cv的两个空杯,用最少的分倒次数把总容量为偶数a的酒(并未要求满瓶)平分,采用直接模拟平分过程的分倒操作;
为了把键盘输入的偶数a通过分倒操作平分为两个i: i=a/2 (i为全局变量),设在分倒过程中:
瓶A中的酒量为a(0<=a<=2*i);
杯B(容积为bv)中的酒量为b(0<=b<=bv);
杯C(容积为cv)中的酒量为c(0<=c<=cv);
我们模拟下面两种方向的分倒操作:
(1)、按 A→B→C 顺序分倒操作;
①、当B杯空(b=0)时,从A瓶倒满B杯;
②、从B杯分一次或多次倒满C杯: 若b>cv-c,倒满C杯,操作③; 若b<=cv-c,倒空B杯,操作①;
③、当C杯满(c=cv)时,从C杯倒回A瓶,分倒操作过程中,用变量n统计分倒次数,每分到一次n增1: 若b=0且a< bv时,步骤①无法实现(即A瓶的酒倒不满B杯)而中断,记n=-1为中断标志,分倒操作过程中若有a=i或b=i或c=i时,显然已达到平分目的,分倒循环结束,用试验函数Probe(a,bv,cv)返回分倒次数n的值; 否则,继续循环操作;
模拟操作描述:
(2)、按 A→C→B 顺序分倒操作;
这一循环操作与(1)实质上是C与B杯互换,相当于返回函数值Probe(a,cv,bv);
试验函数Probe()的引入是巧妙的,可综合模拟以上两种分倒操作,避免了关于cv与bv大小关系的讨论;
同时设计实施函数Practice(a,bv,cv),与试验函数相比较,把n增1操作改变为输出中间过程量a、b、c,以标明具体操作进程;
在主函数main()中,分别输入a、bv,cv的值后,为寻求较少的分倒次数,调用试验函数并比较m1=Probe(a、bv、cv)与m2=Probe(a,bv,cv):
若m1<0 且 m2<0,表明无法平分(均为中断标志);
若m2<0,只能按上述(1)操作;
若0< m1< m2,按上述(1)操作分倒次数较少(即m1),此时调用实施函数Practive(a,bv,cv);
若m1<0,只能按上述(2)操作;
若0< m1< m2,按上述(2)操作分倒次数较少(即m2),此时调用实施函数Practive(a,cv,bv);
实施函数打印整个模拟分倒操作进程中的a,b,c的值,最后打印出最少的分倒次数;
3.程序设计:
4.程序运行示例及其注意事项:
注意:
以上程序中,对m1和m2的全路径判断虽然可以获得分倒次数较少的方法,但这是建立在程序有解的前提之下,而程序有没有解并不能通过对m1和m2的全路径判断来完全确定。 例如,当输入a=10,bv=4,cv=6时,显然没有解,这是程序进入死循环;
那么输入的数据在满足什么条件时才有解呢?
令d=gcd(bv,cv)表示bv和cv的最大公约数,且满足基本条件bv+cv>=(a/2)时,可以证明,当mod(a/2,d)=0时,所输入的数据一定有解,特别地,当bv与cv互质时,a为任意偶数都有解;
1.案例提出:
法国数学家泊松(Poisson)曾提出以下分酒趣题:
某人有一瓶12品脱(容量单位)的酒,同时有容积为5品脱与8品脱的空杯各一个,借助这两个空杯,如何将这瓶12品脱的酒平分?
我们要解决一般的平分酒案例:
借助容量分别为bv与cv(单位为整数)的两个空杯,用最少的分倒次数把总容量为偶数a的酒平分,这里正整数bv、cv与偶数a均从键盘输入;
2.模拟设计:
求解一般的“泊松分酒”问题:借助容积分别为整数bv、cv的两个空杯,用最少的分倒次数把总容量为偶数a的酒(并未要求满瓶)平分,采用直接模拟平分过程的分倒操作;
为了把键盘输入的偶数a通过分倒操作平分为两个i: i=a/2 (i为全局变量),设在分倒过程中:
瓶A中的酒量为a(0<=a<=2*i);
杯B(容积为bv)中的酒量为b(0<=b<=bv);
杯C(容积为cv)中的酒量为c(0<=c<=cv);
我们模拟下面两种方向的分倒操作:
(1)、按 A→B→C 顺序分倒操作;
①、当B杯空(b=0)时,从A瓶倒满B杯;
②、从B杯分一次或多次倒满C杯: 若b>cv-c,倒满C杯,操作③; 若b<=cv-c,倒空B杯,操作①;
③、当C杯满(c=cv)时,从C杯倒回A瓶,分倒操作过程中,用变量n统计分倒次数,每分到一次n增1: 若b=0且a< bv时,步骤①无法实现(即A瓶的酒倒不满B杯)而中断,记n=-1为中断标志,分倒操作过程中若有a=i或b=i或c=i时,显然已达到平分目的,分倒循环结束,用试验函数Probe(a,bv,cv)返回分倒次数n的值; 否则,继续循环操作;
模拟操作描述:
while(!(a==i || b==i || c==i)) { if(!b) /*从A瓶倒满B杯*/ { a-=bv; b=bv; } else if(c==cv) /*从C杯倒回A瓶*/ { a+=cv; c=0; } else if(b>cv-c) /*从B倒满C杯*/ { b-=(cv-c); c=cv; } else /*从B倒C,倒空B杯*/ { c+=b; b=0; } printf("%6d%6d%6d\n",a,b,c); }
(2)、按 A→C→B 顺序分倒操作;
这一循环操作与(1)实质上是C与B杯互换,相当于返回函数值Probe(a,cv,bv);
试验函数Probe()的引入是巧妙的,可综合模拟以上两种分倒操作,避免了关于cv与bv大小关系的讨论;
同时设计实施函数Practice(a,bv,cv),与试验函数相比较,把n增1操作改变为输出中间过程量a、b、c,以标明具体操作进程;
在主函数main()中,分别输入a、bv,cv的值后,为寻求较少的分倒次数,调用试验函数并比较m1=Probe(a、bv、cv)与m2=Probe(a,bv,cv):
若m1<0 且 m2<0,表明无法平分(均为中断标志);
若m2<0,只能按上述(1)操作;
若0< m1< m2,按上述(1)操作分倒次数较少(即m1),此时调用实施函数Practive(a,bv,cv);
若m1<0,只能按上述(2)操作;
若0< m1< m2,按上述(2)操作分倒次数较少(即m2),此时调用实施函数Practive(a,cv,bv);
实施函数打印整个模拟分倒操作进程中的a,b,c的值,最后打印出最少的分倒次数;
3.程序设计:
#include<stdio.h> void practice(int,int,int); /*调用函数声明*/ int i,n,probo(int,int,int); int main() { int a,bv,cv,m1,m2; printf("请输入酒总量(偶数):"); scanf("%d",&a); printf("两空杯容量bv、cv分别为:"); scanf("%d,%d",&bv,&cv); i=a/2; if(bv+cv<i) { printf("空杯容量太小,无法平分!\n"); return; } m1=probo(a,bv,cv); m2=probo(a,cv,bv); if(m1<0 && (m2<0 || m1<m2)) { n=m1; practice(a,bv,cv); } else { n=m2; practice(a,cv,bv); } void practice(int a,int bv,int cv) /*模拟实施函数*/ { int b=0,c=0; printf("平分酒的分发:\n"); printf("酒瓶%d 空杯%d 空杯%d\n",a,bv,cv); printf("%6d%6d%6d\n",a,b,c); while(!(a==i || b==i || c==i)) { if(!b) { a-=bv; b=bv; } else if(c=cv) { a+=cv; c=0; } else if(b>cv-c) { b-=(cv-c); c=cv; } else { c+=b; b=0; } printf("%6d%6d%6d\n",a,b,c); } printf("平分酒共分倒%d次\n",n); } int probo(int a,int bv,int cv) /*试验函数*/ { int n=0,b=0,c=0; while(!(a==i || b==i || c==i)) { if(!b) if(a<bv) { n=-1; break; } else { a-=bv; b=bv; } else if(c==cv) { a+=cv; c=0; } else if(b>cv-c) { b-=(cv-c); c=cv; } else { c+=b; b=0; } n++; } return(n); }
4.程序运行示例及其注意事项:
请输入酒总量(偶数):12 两空杯容量bv、cv分别为:5,8 平分酒的方法: 酒瓶12 空杯8 空杯5 12 0 0 4 8 0 4 3 5 9 3 0 9 0 3 1 8 3 1 6 5 平分酒共分倒6次
注意:
以上程序中,对m1和m2的全路径判断虽然可以获得分倒次数较少的方法,但这是建立在程序有解的前提之下,而程序有没有解并不能通过对m1和m2的全路径判断来完全确定。 例如,当输入a=10,bv=4,cv=6时,显然没有解,这是程序进入死循环;
那么输入的数据在满足什么条件时才有解呢?
令d=gcd(bv,cv)表示bv和cv的最大公约数,且满足基本条件bv+cv>=(a/2)时,可以证明,当mod(a/2,d)=0时,所输入的数据一定有解,特别地,当bv与cv互质时,a为任意偶数都有解;
相关文章推荐
- Khan公开课 - 统计学学习笔记:(四)泊松分布、大数定理
- 泊松分酒
- 泊松分布与指数分布
- 我们应该怎样看待泊松分布???到底什么泊松分布???1。
- 图像处理之添加高斯与泊松噪声
- PCL实现泊松表面重建
- 二项分布 & 泊松分布 & 指数分布
- 泊松分布和指数分布:10分钟教程
- 泊松分布和指数分布
- 十分钟学习泊松分布
- 图像处理之添加高斯与泊松噪声
- 泊松分酒问题
- 泊松过程
- 如何看:泊松分布???
- 【随机过程】随机过程之泊松过程的直观理解
- 泊松分布与指数分布的区别
- 泊松图像编辑(Poisson image editing)
- 概率论05 离散分布-伯努利-二项-泊松-几何分布
- 泊松曲面重建
- 泊松分酒问题