关于递推算法求解约瑟夫环问题P(n,m,k,s)
2017-03-23 13:02
302 查看
一. 问题描述
已知n个人,分别以编号1,2,3,...,n表示,围坐在一张圆桌周围。从编号为k的人开始报数1,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出列,求最后一个出列人的编号,可记为P(n,m,k),或记为P(n,m,k,s = 1),其中s为起始编号。
[b]二. 递归求解
[/b]
n(假设n值很大,而k、m值都很小)个人围成一圈,从k开始以m为步长报数,第k+m-1个人出列;于是转化为n-1个人围成一圈,从(k+m-1)+1开始以m为步长报数,第(k+m)+m-1个人出列;再转化为求n-2个人围成一圈,从(k+2m-1)+1开始以m为步长报数,第(k+2m)+m-1个人出列;依次类推,直至只剩1个人围成一圈,该人出列即为问题的解。有如下推导过程:
因为第一个出圈者是k+m-1,则下一个起始报数者k+m,原圈可增加一套新编号a,用1表示k+m,2表示k+m+1,依此类推,n则表示k+m-1,于是原圈又可对应至新环:1,2,......,n-1,n ------ ①。
因为k+m-1将出圈,即①中n将出圈,余下n-1人,于是有:1,2,......,n-1 ------ ②,对②求P(n-1,m,1),则P(n > 1,m,k) = (P(n-1,m,1) + (k + m - 2)) % n + 1 ------ ⑴(取模前先减1,取模后再加1,以保证落在[1,n]这个区间之上)。由于形如(k + num) % n = (k % n + num) % n (num >= 0)是成立的,所以当k>n或m>n时,⑴也是成立的。
当k=1,有P(n > 1,m,1) = (P(n-1,m,1) + m - 1) % n + 1 ------ ⑵,下文的Josephus_by_k_eq_1(n, m, p = 1, i = 1)实现了⑵。
一般地,P(1,m,k) = P(1,1,1) = 1 ------ ⑶。
由⑵可知P(n-1,m,1) = (P(n-2,m,1) + m - 1) % (n-1) + 1 ------ ⑷,于是P(n,m,k) 的求解可分作两步完成,下文的Josephus_by_k(n, m, k)实现了这一思想:
当约瑟夫环不是用1~n进行编号时,而是用1 + (s-1)~n + (s-1)进行任意编号,最后出圈者P(n,m,k,s) = [b]P(n,m,k-[b](s-1)) [/b]+ (s-1) [/b]------ ⑸,下文的Josephus_by_k_and_s(n, m, k, s)实现了 ⑸。
需特别指出的是,上述[b]推导过程并没有直接得到P(n,m,k > 1)的某种递推关系,只是解决了P(n,m,k = 1)这个特列的递推关系。对于⑵有人给出如下的类似描述,实在费解。因为其描述中k最终实际是一个无关的参数,但P(n,m,k)却与k有极大的关联[/b]。事实上,P(3,2,3) = 2,而P(3,2,1) = 3 。
三. [b]P(n,m,1) = (P(n-1,m,1) + m - 1) % n + 1的Javascript[b]算法实现:Josephus_by_k_eq_1(n, m, p = 1, i = 1)[/b][/b]
[b]四. P(n,m,k) = (P(n-1,m,1) + (k + m - 2)) % n + 1[b][b]的[b][b]Javascript[/b]算法实现:Josephus_by_k(n, m, k)[/b][/b][/b][/b]
[b][b][b][b][b][b][b][b][b][b][b][b][b][b][b][b]五.[b]P(n,m,k,s) = [b]P(n,m,k-[b](s-1)) [/b]+ (s-1)[b][b][b]的[b][b]Javascript[/b]算法实现:Josephus_by_k_and_s(n, m, k, s)[/b][/b][/b][/b][/b][/b][/b][/b][/b][/b][/b][/b][/b][/b][/b][/b][/b][/b][/b][/b][/b][/b]
已知n个人,分别以编号1,2,3,...,n表示,围坐在一张圆桌周围。从编号为k的人开始报数1,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出列,求最后一个出列人的编号,可记为P(n,m,k),或记为P(n,m,k,s = 1),其中s为起始编号。
[b]二. 递归求解
[/b]
n(假设n值很大,而k、m值都很小)个人围成一圈,从k开始以m为步长报数,第k+m-1个人出列;于是转化为n-1个人围成一圈,从(k+m-1)+1开始以m为步长报数,第(k+m)+m-1个人出列;再转化为求n-2个人围成一圈,从(k+2m-1)+1开始以m为步长报数,第(k+2m)+m-1个人出列;依次类推,直至只剩1个人围成一圈,该人出列即为问题的解。有如下推导过程:
因为第一个出圈者是k+m-1,则下一个起始报数者k+m,原圈可增加一套新编号a,用1表示k+m,2表示k+m+1,依此类推,n则表示k+m-1,于是原圈又可对应至新环:1,2,......,n-1,n ------ ①。
因为k+m-1将出圈,即①中n将出圈,余下n-1人,于是有:1,2,......,n-1 ------ ②,对②求P(n-1,m,1),则P(n > 1,m,k) = (P(n-1,m,1) + (k + m - 2)) % n + 1 ------ ⑴(取模前先减1,取模后再加1,以保证落在[1,n]这个区间之上)。由于形如(k + num) % n = (k % n + num) % n (num >= 0)是成立的,所以当k>n或m>n时,⑴也是成立的。
当k=1,有P(n > 1,m,1) = (P(n-1,m,1) + m - 1) % n + 1 ------ ⑵,下文的Josephus_by_k_eq_1(n, m, p = 1, i = 1)实现了⑵。
一般地,P(1,m,k) = P(1,1,1) = 1 ------ ⑶。
由⑵可知P(n-1,m,1) = (P(n-2,m,1) + m - 1) % (n-1) + 1 ------ ⑷,于是P(n,m,k) 的求解可分作两步完成,下文的Josephus_by_k(n, m, k)实现了这一思想:
步骤一:通过等式⑶、⑷递推求解P(n-1,m,1) 步骤二:通过等式⑴求解P(n,m,k)
当约瑟夫环不是用1~n进行编号时,而是用1 + (s-1)~n + (s-1)进行任意编号,最后出圈者P(n,m,k,s) = [b]P(n,m,k-[b](s-1)) [/b]+ (s-1) [/b]------ ⑸,下文的Josephus_by_k_and_s(n, m, k, s)实现了 ⑸。
需特别指出的是,上述[b]推导过程并没有直接得到P(n,m,k > 1)的某种递推关系,只是解决了P(n,m,k = 1)这个特列的递推关系。对于⑵有人给出如下的类似描述,实在费解。因为其描述中k最终实际是一个无关的参数,但P(n,m,k)却与k有极大的关联[/b]。事实上,P(3,2,3) = 2,而P(3,2,1) = 3 。
P(n, m, k) = 1 (i = 1) P(n, m, k) = (P(i - 1, m, k ) + m - 1) % n + 1 (i > 1) 其下列算法实现虽然在注释中给k定义为起始报数位置,实际上不是P(n, m, k)中k的含义,而是代表P(n-1, m, 1) long Josephus(long n,long m,long k){ //参数分别为:总人数,出圈步长,起始报数位置, for (long i = 1; i <= n; i++) k = (k + m - 1) % i + 1; return k; //返回最后一人的位置 }
三. [b]P(n,m,1) = (P(n-1,m,1) + m - 1) % n + 1的Javascript[b]算法实现:Josephus_by_k_eq_1(n, m, p = 1, i = 1)[/b][/b]
/** * 约瑟夫环(编号1~n)问题求最后出圈者P(n,m,k = 1) * * @para int n 总人数 * @para int m 报数步长 * @para int p P(n-1,m,1) * @para int i 迭代控制变量 * @return int 最后出圈者 */ function Josephus_by_k_eq_1(n, m, p = 1, i = 1) { if (i > n) { return p; //返回最后出圈者 } else { p = (p + m - 1) % i + 1; i = i + 1; return Josephus_by_k_eq_1(n, m, p, i); } }
[b]四. P(n,m,k) = (P(n-1,m,1) + (k + m - 2)) % n + 1[b][b]的[b][b]Javascript[/b]算法实现:Josephus_by_k(n, m, k)[/b][/b][/b][/b]
/** * 约瑟夫环(编号1~n)问题求最后出圈者P(n,m,k) * * @para int n 总人数 * @para int m 报数步长 * @para int k 起始报数者 * @return int 最后出圈者 */ function Josephus_by_k(n, m, k) { return (Josephus_by_k_eq_1(n - 1, m) + (k + m - 2)) % n + 1; }
[b][b][b][b][b][b][b][b][b][b][b][b][b][b][b][b]五.[b]P(n,m,k,s) = [b]P(n,m,k-[b](s-1)) [/b]+ (s-1)[b][b][b]的[b][b]Javascript[/b]算法实现:Josephus_by_k_and_s(n, m, k, s)[/b][/b][/b][/b][/b][/b][/b][/b][/b][/b][/b][/b][/b][/b][/b][/b][/b][/b][/b][/b][/b][/b]
/** * 约瑟夫环(编号1+(s-1)~n+(s-1))问题求最后出圈者P(n,m,k,s) * * @para int n 总人数 * @para int m 报数步长 * @para int k 起始报数者 * @para int s 起始编号 * @return int 最后出圈者 */ function Josephus_by_k_and_s(n, m, k, s) { return Josephus_by_k(n, m, k - (s - 1)) + (s - 1); }
相关文章推荐
- 关于递推算法求解约瑟夫环问题P(n,m,k,s)
- 关于n皇后问题的递归求解,有详细的步骤说明。
- 求解 关于 套汇问题 要求 使用 C++
- 关于一元二次方程求解问题(java)
- 关于 约瑟夫环 问题
- [算法思考]关于2-sat判定求解中“同一组内必须选择”问题的思考
- Java算法--递推算法 求解兔子产子问题或斐波那契数列问题
- 关于存储过程问题(高分求解,分不够可以再给)
- 关于2-sat判定求解中“同一组内必须选择”问题的思考
- 关于约瑟夫环的问题
- 关于约瑟夫环用list实现遇到的奇怪问题
- 关于Tomcat死锁的问题,在线求解
- 关于A*算法求解最短路径问题的一些知识
- 关于约瑟夫环的问题 的通解
- 在线求解关于视图的解决问题,附代码和图
- 2种方法求解约瑟夫环问题
- 求解约瑟夫环问题
- 关于字段和局部变量作用域冲突的问题,求解.......
- 关于类得数据成员的大小问题。求解。
- 关于cuda编程的一个问题(求解)