约瑟夫环问题

 

约瑟夫环问题

n个人围成一圈从第一个人开始依次从1到m循环报数,当报到m的时候此人出圈,直到圈中只剩一人为止。

求最后一个人的原始编号。
int yuesefu(int n,int m)
{
    int i,r=0;
    for (i=2;i<=n;i++) r=(r+m)%i;
    return r+1;
}

最近有人问我这个代码看不明白,如何解释?

想起n年前刚毕业时,曾经有个面试官问过我同样的问题,面试官说你是数学系的吧,问个简单的算法问题,

我当时脑子里一片空白,发呆了几分钟后说不会,现在想想真是给数学系丢人啦...

最简单的想法自然是搞一个循环链表,外加一个计数器,%3 == 0 就删节点,直到链表只有一个节点为止。

现在说说上面这种解法如何理解,上面的做法其实是个逆过程,从2人报m得出剩下人的序号t2,再算出t2在

上一个3人序列中的序号t3,然后一步步得出原始序列n中的编号tn。关键就在于(t2,t3),(t3, t4)...间

的关系,我们这么来看:

n序列1,2,3....n,报m退出,最后结果记为t(n)

第一次m退出得到1,2,3...m-1, m+1,m+2...n

再报数顺序为 m+1, m+2, ...n, 1,2...m-1

假设1,2,3...n-1序列最后结果为t(n-1),假设我们知道t(n-1),

t(n)其实就是数组m+1,m+2,...n,1,2...m-1中第t(n-1)个元素的值,

不难看出数组中第k个元素值就是(m+k)%n,因此t(n)=(m+t(n-1))%n,

那么函数里for (i=2;i<=n;i++) r=(r+m)%i; 就是做从n=2开始计算t(n)的循环而已

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值