约瑟夫环问题
n个人围成一圈从第一个人开始依次从1到m循环报数,当报到m的时候此人出圈,直到圈中只剩一人为止。
求最后一个人的原始编号。
int yuesefu(int n,int m)
{
}
最近有人问我这个代码看不明白,如何解释?
想起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)的循环而已