第18 题: 题目:n 个数字(0,1,…,n-1)形成一个圆圈,从数字0 开始每次从这个圆圈中删除第m 个数字(第一个为当前数字本身,第二个为当前数字的下一个数 字)。

这篇博客讨论了Josephus问题的推广,即在n个数字形成的圆圈中,从数字1开始每次删除第m个数字,求解最后剩下的数字。文章介绍了利用《具体数学》中的知识来解决此类问题,并提供了算法实现,包括一个改进的算法来计算最后的幸存者位置。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

当一个数字删除后,从被删除数字的下一个继续删除第m 个数字。

求出在这个圆圈中剩下的最后一个数字。


思路:

      把这个题目中的开始数字改下以便下面的说明,n 个数字(1,…,n-1,n)形成一个圆圈,从数字1 开始每次从这个圆圈中删除  第(第说明与开始数字无关)m 个数字(第一个为当前数字本身,第二个为当前数字的下一个数 字)。

     这个是Josephus问题的推广(Josephus问题是m = 3)。

     这个题目出题人的意图应该是采用模拟的方法吧,这种方法网上很多。正好前段时间上了具体数学这门课,下面利用《具体数学》中提到的知识来解决这样的问题。可以参考具体数学第三章第三节。

    下面是对原文的一段摘抄:(Josephus问题是m = 3)

     每当一个人越过,我们就赋予一个新的数。于是,1和2变成了n+1和n+2,则3被执行;4和5变成n+3和n+4,则6被执行;……,3k+1和3k+2变成n+2k+1和n+2k+2,则3k+3被执行;……,则3n被执行(或留下幸存),例如当n=10,数是

          1          2          3          4          5          6          7          8          9          10

         11       12                    13        14                    15        16                     17

          18                               19        20                                 21                    22

                                              23        24                                                          25

                                              26                                                                       27

                                              28

                                             29

                                              30

 数3k最后以消除第k个人而告终。所以如果我们能计算出人数3n的原先的数,则我们能断定谁是幸存者。

    若N>n,人数N一定要有一个以前的数,且我们能找到它。如下:我们有N=n+2k+1或N=n+2k+2,因此k= (int)((N-n-1)/2),以前的数分别是3k+1或3k+2,也就是说,它是3k+(N-n-2k)=k+N-n,因此我们能计算幸存者数J3(n)如下:

    N = 3n;

    while  N>n    do     N:=(int)  ((N-n-1)/2 ) + N -n;

   J3(n)  :=  N.

   利用D = 3n+1-N来替换N,我们可以得到改进的算法:

  D:=1;

  while  D <=  2n    do   D :=  ceil(   3*D/2 );//ceil是c中的取上整函数

   J3(n) :=  3n + 1 -D.

 同样的道理消除第m个人。

#include <iostream>
#include <cmath>

using namespace std;

int main()
{
	double a = 1.0;
	int m = 0,n = 0;

	cin >> m >> n;

	while ( a <= (m-1)*n )
	{
		a = ceil ( m*a/(m-1) );
	}

	cout << (m*n + 1 - (int)a  - 1) << endl;//原文是从0开始,在此基础上-1.
	return 0;
}


     


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值