约瑟夫环问题总结
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
*a = [n]; //设置个用来存储n个人是否出圈1表示在圈内0表示在圈外 for ( i=n-2; i>=0; i--) //存储下个人编号 { a[i] = i + 1; } a[n-1] = 0; //最后个人下位是第个人 pos = n - 1; //当前位置 do { for ( i=0; i<m-1; i) pos = a[pos]; a[pos] = a[a[pos]]; } while (pos != a[pos]); delete a; pos + 1; } //很巧妙思路方法直接确定出列人并不断改变长度 Fun_6( n, m) { *a = [n]; //设置个用来存储n个人编号 for ( i=0; i<n; i) //注意C语言中下标从0开始 { a[i] = i + 1; } pos = (m - 1) % n;//这是第个要出列人下标 while (n > 1) // 当队列中还有不止个人时候要就进行出列动作 { for ( i=pos; i<n-1; i) //这个家伙走了以后后面人应该依次顶上来
time_t endTime; time(&startTime); for ( i=10; i<11; i) cout << Fun_1(i, 8); time(&endTime); cout << "No.1 time = " << dftime(endTime, startTime) << endl; time(&startTime); for ( i=10; i<11; i) cout << Fun_2(i, 8); time(&endTime); cout << "No.2 time = " << dftime(endTime, startTime) << endl; time(&startTime); for ( i=10; i<11; i) cout << Fun_3(i, 8); time(&endTime); cout << "No.3 time = " << dftime(endTime, startTime) << endl; time(&startTime); for ( i=10; i<11; i) cout << Fun_4(i, 8); time(&endTime); cout << "No.4 time = " << dftime(endTime, startTime) << endl; time(&startTime); for ( i=10; i<11; i) cout << Fun_5(i, 8); time(&endTime); cout << "No.5 time = " << dftime(endTime, startTime) << endl; time(&startTime); for ( i=10; i<11; i) cout << Fun_6(i, 8); time(&endTime);
{ a[i] = i + 1; } s = 1; //累计出圈人数设初值为1那最后个就不用出圈了 count = 0; //计数器数到m就归零 while(s < n) { for ( i=0; i<n; i)//只要还有超过1个人在圈里就不断遍历 { (a[i] 0) //编号为0表示此人已经出圈 continue; count; //报次数 (count m) //报数为m那个人出圈 { a[i] = 0; //设此位置编号为0表示此人已经出圈 s; //出圈人增加个 count = 0; //计数器归零 } } } pos; for ( i=0; i<n; i) //遍历看看还有谁没有出圈找就是他 { (a[i] != 0) { pos = a[i]; ; } } delete a; pos; } //采用了计数器思路方法也使用了但中存储不是个人编号而是是否出圈信息 Fun_2( n, m)
*a = [n]; //设置个用来存储n个人是否出圈1表示在圈内0表示在圈外 for ( i=n-2; i>=0; i--) //存储下个人编号 { a[i] = i + 1; } a[n-1] = 0; //最后个人下位是第个人 s = 0; //累计出圈人数设初值为1那最后个就不用出圈了 count = 0; //计数器 pos; //当前位置 nextPos = 0;//下位置 while(s < n) { pos = nextPos;//获取当前位置 nextPos = a[pos];//获取当前位置下位置 count; (count m)//改变当前位置下位置 { count = 0; //计数器归零 s; //累计出圈人 a[pos] = a[nextPos]; } } delete a; (nextPos != 0) nextPos; n; } //很巧妙思路方法Fun_4个改进 Fun_5( n, m) {
temp = s; s = s->next; } //把数到m人从链表中删除 temp->next = s->next; delete s; s = temp->next; } pos = s->data; //最后个人 delete s; pos; } /* 数学思路方法: 令f表示i个人玩游戏报m退出最后胜利者编号最后结果自然 是f[n],实际生活中编号总是从1开始我们输出f[n]+1 递推公式 f[1]=0; f=(f[i-1]+m)%i; (i>1) */ // 递归算法 F( n, m) { (n 1) 0; (F(n-1, m) + m) % n; } Fun_8( n, m) { F(n, m) + 1; } //非递归算法 Fun_9( n, m) {
约Hale Waihona Puke Baidu夫环问题算法问题归类总结
疯狂代码 http://CrazyCoder.cn/ ĵ:http:/CrazyCoder.cn/Arithmetic/Article31439.html /* Name: 约瑟夫环问题算法集锦 Copyright: 始发于goal00001111专栏;允许自由转载但必须注明作者和出处 Author: goal00001111搜集整理 Date: 03-12-08 18:14 Description: 有编号从1到NN个人坐成圈报数报到M人出局下位再从1开始 如此持续 直止剩下位为止报告此人编号X 输入N,M求出X 共搜集整理了7类10种算法对于初学者和算法爱好者来说——看了绝对值! */ #<iostream> # <time.h> using std; Fun_1( n, m); Fun_2( n, m); Fun_3( n, m); Fun_4( n, m); Fun_5( n, m); Fun_6( n, m); Fun_7( n, m); Fun_8( n, m); Fun_9( n, m); Fun_10( n, m); ( argc, char* argv) { n, m; //cout << "Input max, step: "; // cin >> n >> m; time_t startTime;
cout << "No.6 time = " << dftime(endTime, startTime) << endl; time(&startTime); for ( i=10; i<11; i) cout << Fun_7(i, 8); time(&endTime); cout << "No.7 time = " << dftime(endTime, startTime) << endl; time(&startTime); for ( i=10; i<11; i) cout << Fun_8(i, 8); time(&endTime); cout << "No.8 time = " << dftime(endTime, startTime) << endl; time(&startTime); for ( i=10; i<11; i) cout << Fun_9(i, 8); time(&endTime); cout << "No.9 time = " << dftime(endTime, startTime) << endl; time(&startTime); for ( i=10; i<11; i) cout << Fun_10(i, 8); time(&endTime); cout << "No.10 time = " << dftime(endTime, startTime) << endl; system("pause"); 0; } //采用了设置个人编号和计数器思路方法屏蔽已经出圈人位置 Fun_1( n, m) { *a = [n]; //设置个用来存储n个人编号 for ( i=0; i<n; i) //注意C语言中下标从0开始
} } } pos; for ( i=0; i<n; i) //遍历看看还有谁没有出圈找就是他 { (a[i] 1) { pos = i + 1; ; } } delete a; pos;
} //采用了队列思路方法每出圈个人就从队列中删除 Fun_3( n, m) { *a = [n]; //设置个用来存储n个人编号 for ( i=0; i<n; i) //注意C语言中下标从0开始 { a[i] = i + 1; } front=0, rear=n-1; //对头front指向第个元素队尾rear指向最后个元素 count = 0; //计数器数到m就归零 while ((front) != (rear))//当队列元素还有个注意这里不需要队列为空而是留个元素 { count; //报次数 (count m) //报数为m那个人出圈 { front = front % n; //将该元素从队列中删除 count = 0; //计数器归零 } //否则把对头元素放到队尾去 { rear = rear % n;//队尾前移以存储从对头转来元素 a[rear] = a[front]; front = front % n; //对头前移指向新元素 } } delete a; a[front]; } //很巧妙思路方法不用屏蔽位置, 需要计数器采用但中存储不是本人编号而是是下个人编号 Fun_4( n, m) {
{ a[i] = a[i+1]; } n--; // 并且整个队列人少了个也就是长度要减掉 pos = (pos + m - 1) % n; //这是下个要出列人 } pos = a[0]; delete a; pos; } //采用循环链表结构来进行删除操作 Fun_7( n, m) { struct node { data; struct node *next; }; struct node * head, *s, *temp; head = struct node;//存储第个人序号信息 head->data = 1; temp = head->next = head; for ( i=2; i<=n; i)//存储所有人序号信息 { s = struct node; s->data = i; s->next = head; temp->next = s; temp = s; } s = head; while (s->next != s) { for ( i=1; i<m; i)//先数m-1个数 {
{ *a = [n]; //设置个用来存储n个人是否出圈1表示在圈内0表示在圈外 for ( i=0; i<n; i) //首先设置所有人都在圈内 { a[i] = 1; } s = 1; //累计出圈人数设初值为1那最后个就不用出圈了 count = 0; //计数器数到m就归零 while(s < n) { for ( i=0; i<n; i)//只要还有超过1个人在圈里就不断遍历 { count a[i]; //若a[i]=0就直接跳过了 (count m) //报数为m那个人出圈 { a[i] = 0; //设此位置编号为0表示此人已经出圈 s; //出圈人增加个 count = 0; //计数器归零