对"泊松分酒”问题的理解

为了方便说明,将容量为12品脱,8品脱,5品脱瓶子分别称为大瓶子,中瓶子,小瓶子。按照下面2种规则中的如何一种可以解决这个问题:

以下是求最短即最优解的方法:
规则:

  1. 大瓶子只能倒入中瓶子

  2. 中瓶子只能倒入小瓶子

  3. 小瓶子只能倒入大瓶子

  4. 小瓶子只有在已经装满的情况下才能倒入大瓶子

  5. 若小瓶子被倒空,则无论中瓶子是否满,应马上从中瓶子倒入小瓶子

之所以要规定倒酒的顺序是为了防止状态重复。而根据这5条规则,大瓶子每次倒入中瓶子的酒总是8品脱,小瓶子每次倒入大瓶子的酒总是5品脱。(请结合下面的表来理解这句话,理解这点很重要)

有了上面的规定后,倒酒的顺序就确定下来了:

设大,中,小三个瓶子容量分别是C1,C2,C3,需要倒出的容量是R

则实际上要是我们能将容量为R的酒倒到中瓶子和小瓶子中就可以啦(有点废话)

设大瓶子倒满中瓶子X次,从小瓶子中倒入大瓶子Y次。

那么显然由大瓶子累次倒入中瓶子和小瓶子总共C2X的酒。而由小瓶子倒入大瓶子一共有C3Y的酒。

那么最终,小瓶子和中瓶子剩余的酒显然就是 C2X - C3Y

因此,泊松分酒问题实质上转化为下面的不定方程是否有正整数解的问题:

C2X - C3Y = R

对于我们的问题,

C1=12,C2=8,C3=5,R=6

倒酒规则实质上相当于解下面这个不定方程:

8X - 5Y = 6 ( 限定 X > 0 ,Y > 0 )

最小整数解是 X=2,Y= 2

表示倒满8品脱的瓶子2次,5品脱的瓶子倒空2次

那么8品脱的瓶子和5品脱的瓶子剩酒总量必然是 8 * 2 – 5 * 2 = 6

#include<bits/stdc++.h>
using namespace std;
#define A 10
#define B 7
#define C 3
void A_to_B();
void B_to_C();
void C_to_A();
int a=A;
int b=0;
int c=0;
int main(){
	while(a!=A/2){
		if(b==0)
			A_to_B();
		if(c==C)
			C_to_A();
		else if(b!=0)
			B_to_C();		
	}
	return 0;
}

void A_to_B(){
	b=a>B?B:a;
	a-=b;
	printf("\na->b:\t a=%d\tb=%d\tc=%d\t",a,b,c);
}
void B_to_C(){
	int n=c;
	c=b+c>C?C:b+c;
	b-=c-n;
	printf("\nb->c:\t a=%d\tb=%d\tc=%d\t",a,b,c);	
}
void C_to_A(){
	a+=c;
	c=0;
	printf("\nc->a:\t a=%d\tb=%d\tc=%d\t",a,b,c);		
}

如果是10次的话,因为我们求的是a->b 和c->a的值,而b->c的值即为其和再减去1,那么10的最优解就是9了

还有一些方法,是求能否分成功,但不一定是最优解:
法一:
根据扩展欧几里得定理:
aX+bY=gcd(a,b)
即只要d%gcd(a,b)==0,那么就算成功

法二:
小桶是a,中桶是b,大桶是c,目标是d。
不断扩大a的倍数
a*n%b==d,就算成功

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值