我将参加OBI(巴西信息学奥林匹克,英语),我正在尝试过去几年的一些练习。但是我找不到这个练习的解决方案(我翻译它,所以可能会有一些错误):
巧克力比赛
卡洛斯和宝拉刚买了一袋巧克力球。因为他们会吃 一切都太快了,他们做了一场比赛:
- 他们将一个接一个地交替吃饭(Paula总是开始)。
- 每次,他们只能吃1到M个球,M由Paula的母亲决定,所以他们不会窒息。
- 如果一个人在他/她的回合中吃了K球,那么下一个就不能吃K球了。
- 任何不能按照上述规则进行比赛的人都会输球。
在下面的例子中,M = 5和20球,Carlos赢了:
Who plays How many ate Balls left
20
Paula 5 15
Carlos 4 11
Paula 3 8
Carlos 4 4
Paula 2 2
Carlos 1 1
请注意,最后,卡洛斯无法赢得2球,因为保拉在最后一回合吃了2球。但是保拉不能吃掉最后一个球,因为卡洛斯在最后一回合吃了1分,所以保拉不能上场输球。
两者都非常聪明并且发挥最佳。如果有一系列转弯确保他/她的胜利独立于其他转弯,他/她将播放这些序列。
任务:
你的任务是找出谁将赢得比赛,如果两者都发挥最佳。
输入:
输入只包含一个测试组,应该从标准输入(通常是键盘)中读取。
输入有2个整数N(2≤N≤1000000)和M(2≤M≤1000),N是球的数量,M是每回合允许的数量。
输出:
您的程序应在标准输出中打印一行,其中包含获胜者的姓名。
示例:
Input: Output:
5 3 Paula
20 5 Carlos
5 6 Paula
我一直在努力解决问题,但我不知道如何解决。
C中的解决方案可以在这里找到:http://olimpiada.ic.unicamp.br/passadas/OBI2009/res_fase2_prog/programacao_n2/solucoes/chocolate.c.txt但我无法理解算法。有人在另一个网站上发布了有关此问题的问题,但没有人回复。
你能解释一下算法吗?
以下是该计划的预期成果:http://olimpiada.ic.unicamp.br/passadas/OBI2009/res_fase2_prog/programacao_n2/gabaritos/chocolate.zip
答案 0 :(得分:3)
我们假设我们有一个布尔函数FirstPlayerWin(FPW),它带有两个参数:左边的巧克力数量(c)和最后一个移动(l),即上一轮取得的巧克力数量,即0在第一步。当且仅当第一个在这种情况下比赛的球员获得胜利时,例程才返回真假。
基本情况是任何l!= 1
的FPW(0,l)= false否则,为了计算FPW(c,l),如果对于任何x <= M,x <= c,x!= 1,FPW(c-x,x),则FPW(c,l)为真。是假的。否则就是假的。这就是动态编程踢的地方,因为现在FPW的计算减少到计算较小的c值的FPW。
但是,存储此公式的条目将需要N * M个表条目,而您指向的解决方案仅使用2N个表条目。
这是因为如果FPW(c,0)为真(如果在巧克力计数c处有任何移动,则第一个玩家获胜)但是对于x>,FPW(c,x)为假。 0,FPW(c,y)for和y!= x必须为真。这是因为如果拒绝移动x会使玩家失败,即玩家只能通过玩x获胜,那么当y被禁止时,移动x可用。因此,它足以存储任何计数&#39; c&#39;最多一个禁止移动导致玩家失去那里。因此,您可以重构动态编程问题,以便不是存储完整的二维数组FPW(c,x),而是存储两个数组,一个存储值FPW(c,0),另一个存储导致的单个禁止移动第一个失败而不是获胜的球员,如果有的话。
如何获得引用的C程序的确切文本留给读者练习。
答案 1 :(得分:0)
我认为这是动态编程中另一个极其伪装的练习。游戏的状态由两个量描述:剩余球数和前一次移动中吃的球数。当剩余的球数<= M时,游戏要么赢了(如果剩下的数量不等于前次移动中吃的数量)要么丢失(如果是 - 你不能吃掉所有的球,并且你的对手可以吃掉你离开的球。)
如果你已经计算出H的所有球数的输赢情况,以及前一位球员吃过的所有球数并将其写在桌子上,那么你可以找出所有球的答案球数达H + 1。在前一次移动中吃H + 1球和k球的球员会考虑所有可能性 - 除了k的非法值之外,为i = 1到M吃i球,留下H + 1-i球的位置和之前的球移动我他们可以使用桌子给出双赢球的最大胜利情况,试图找到合法的k,让他们获胜。如果他们能找到这样的值,那么H + 1 / k位置就是胜利。如果没有,这是一个损失,所以他们可以扩展表格以覆盖H + 1球,依此类推。
我没有完成所有未注释的示例代码,但看起来它可能正在执行类似的操作 - 使用动态编程(如递归来构建表)。