企业网站实验报告,年前做网站的好处,福州模板建站代理,创意网站设计团队详解约瑟夫环问题及其相关的C语言算法实现约瑟夫环问题N个人围成一圈顺序编号#xff0c;从1号开始按1、2、3......顺序报数#xff0c;报p者退出圈外#xff0c;其余的人再从1、2、3开始报数#xff0c;报p的人再退出圈外#xff0c;以此类推。请按退出顺序输出每个退出人…详解约瑟夫环问题及其相关的C语言算法实现约瑟夫环问题N个人围成一圈顺序编号从1号开始按1、2、3......顺序报数报p者退出圈外其余的人再从1、2、3开始报数报p的人再退出圈外以此类推。请按退出顺序输出每个退出人的原序号算法思想用数学归纳法递推。无论是用链表实现还是用数组实现都有一个共同点要模拟整个游戏过程不仅程序写起来比较烦而且时间复杂度高达O(nm)若nm非常大无法在短时间内计算出结果。我们注意到原问题仅仅是要求出最后的胜利者的序号而不是要读者模拟整个过程。因此如果要追求效率就要打破常规实施一点数学策略。为了讨论方便先把问题稍微改变一下并不影响原意问题描述n个人(编号0~(n-1))从0开始报数报到(m-1)的退出剩下的人继续从0开始报数。求胜利者的编号。我们知道第一个人(编号一定是m%n-1) 出列之后剩下的n-1个人组成了一个新的约瑟夫环(以编号为km%n的人开始):k k1 k2 ... n-2, n-1, 0, 1, 2, ... k-2并且从k开始报0。现在我们把他们的编号做一下转换k -- 0k1 -- 1k2 -- 2......k-2 -- n-2k-1 -- n-1变换后就完完全全成为了(n-1)个人报数的子问题假如我们知道这个子问题的解例如x是最终的胜利者那么根据上面这个表把这个x变回去不刚好就是n个人情况的解吗变回去的公式很简单相信大家都可以推出来x(xk)%n如何知道(n-1)个人报数的问题的解对只要知道(n-2)个人的解就行了。(n-2)个人的解呢当然是先求(n-3)的情况——这显然就是一个倒推问题好了思路出来了下面写递推公式令f[i]表示i个人玩游戏报m退出最后胜利者的编号最后的结果自然是f[n]递推公式f[1]0;f[i](f[i-1]m)%i; (i1)实现方法一、循环链表建立一个有N个元素的循环链表然后从链表头开始遍历并计数如果基数i m则踢出该元素继续循环直到当前元素与下一个元素相同时退出循环#include #include #include typedef struct lnode{int pos;struct lnode *next;} lnode;/*** 构建循环链表循环遍历*/void create_ring(lnode **root, int loc, int n){lnode *pre, *current, *new;current *root;pre NULL;while (current ! NULL) {pre current;current current-next;}new (lnode *)malloc(sizeof(lnode));new-pos loc;new-next current;if (pre NULL) {*root new;} else {pre-next new;}// 循环链表if (loc n) {new-next *root;}}/*** 约瑟夫环*/void kickoff_ring(lnode *head, int p){int i;lnode *pre, *pcur;pre pcur head;while (pcur-next ! pcur) {for (i 1; i p; i ) {pre pcur;pcur pcur-next;}printf(%d , pcur-pos);pre-next pcur-next;free(pcur);pcur pre-next;}printf(%d\n, pcur-pos);free(pcur);}void print_ring(lnode *head){lnode *cur;cur head;while (cur-next ! head) {printf(%d , cur-pos);cur cur-next;}printf(%d\n, cur-pos);}int main(){int i, p, n;lnode *head;while (scanf(%d %d, n, p) ! EOF) {// 构建循环链表for (i 1, head NULL; i n; i )create_ring(head, i, n);// 约瑟夫环if (p ! 1)kickoff_ring(head, p);elseprint_ring(head);}return 0;}/**************************************************************Problem: 1188User: wangzhengyiLanguage: CResult: AcceptedTime:110 msMemory:912 kb****************************************************************/二、数组模拟思想跟循环链表类似少了构建循环链表的过程#include #include int main(){int i, index, p, n, remain, delete[3001], flag[3001] {0};while (scanf(%d %d, n, p) ! EOF) {remain n;index 0;while (remain 1) {for (i 0; i n; i ) {if (flag[i] 0) {// 报数index ;// 报p者退出圈外if (index p) {// 退出圈外flag[i] 1;// 重新报数index 0;delete[remain - 1] i 1;remain --;}}}}// 输出每个退出人的序号for (i n - 1; i 0; i --) {if (i 0) {printf(%d\n, delete[i]);} else {printf(%d , delete[i]);}}}return 0;}三、数学推导#include int main(void){int i, n, m, last;while (scanf(%d, n) ! EOF n ! 0) {// 接收报数scanf(%d, m);// 约瑟夫环问题for (i 2, last 0; i n; i ) {last (last m) % i;}printf(%d\n, last 1);}return 0;}相关阅读:C#基础之数据类型转换Android 异步获取网络图片并处理导致内存溢出问题解决方法jquery中取消和绑定hover事件的实现代码Spring整合websocket整合应用示例(下)win7系统在word中插入excel公式的方法JavaScript将数据转换成整数的方法Android 加密解密字符串详解Android列表实现(3)_自定义列表适配器思路及实现代码Linux系统下Git的基本配置和使用示例jquery map方法使用示例详解在Java的Struts2框架中配置Action的方法获取控件大小和设置调整控件的位置XY示例Win10 10074预览版键盘输入延迟是什么原因如何解决mysql分表和分区的区别浅析