约瑟夫问题(Josephus problem)
来源:互联网 发布:淘宝拍照技巧小摄影棚 编辑:程序博客网 时间:2024/06/06 19:56
问题概述:
非原装正版问题,但是道理还是那个道理
N个人编号1~N,围坐成一个圆圈。从1号人开始传递一个热土豆,经过M次传递后那这热土豆的人被清除离座,由坐在后面的人拿起热土豆继续进行游戏。最后剩下的人获胜。
ex: M=0,N=5 清除顺序:1->2->3->4->5 ; M=1,N=5 清除顺序:2->4->1->5->3;
(注意的是:这个问题描述和网上的部分问题描述不一致,在于 每次 开始都会从被排除的下一个人开始,M是 间隔gap,而不是报数的个数number。)
ps:书上给出的代码我已经改成我的理解,以及最后的数学方法也是按自己的理解得到输出结果。
代码实现:
list和iterator:
(书上给出的答案加以修改)
按照作者的观点,每次得到 M' =M mod N,这样来避免由于M>N造成的转圈重复计数,然后分出两种情况来优化每次循环的次数即M‘,情况如下
- M’>N/2 , 从当前位置反方向走 即 itr--
- M'<=N/2 , 从当前位置正方向走 即 itr++
用了 list 给出的 删除erase 和 iterator 给出的位置,故每次删除是真的从这一圈人中去除了,人数也会相应的减少。
优点:可以精神集中在解决 主要问题上,且 易于理解和实现。
时间复杂度:
T(N)=O(MN) 由于有N个数,然后每次最多移动M次
#include#include
int main(){int n, m, i, j, num, mp;cout << "Please input the number of people N and the gap M:" << endl;cin >> n >> m;num = n; //num存储每次的剩余人数list L;for (i = 1; i <= n; ++i) L.push_back(i);list ::iterator ite = L.begin();for (i = 0; i < n; ++i) {mp = m%num; //防止重复计数浪费资源if (mp <= num / 2)for (j = 0; j < mp; ++j) {++ite;if (ite == L.end())ite = L.begin();}else { mp = num - mp; //反方向走是距离差for (j = 0; j < mp; ++j)if (ite == L.begin())ite = --L.end();elseite--;}num--;cout << *ite;ite = L.erase(ite);if (ite == L.end())ite = L.begin();}system("pause");return 0;}
array:
把上述问题用数组实现,由于数组是连续分配的一段空间,不能真的删除,那对应该删除的人,只是标记上该元素被删除(使用一个附加的位域(bin field),我就是用一个bool数组Tag 来标记:true 未删除 | false 删除)
循环的时候,如果Tag[index]==true那么在M的循环中计数,当计数完成后,还要确定下一个是否也满足未删除状态,直到找到一个未删除的,然后将其删除
ps:应该也可以把标记数组,记为0和1这样可以用数字的累加代替判断
优点:可以体验全过程自己实现,以及能正确实现的快感...
时间复杂度:
T(N)=O(N^2) 由于有N个数,然后 M<=每次移动<N,因为要依次判断每个元素是否被删除...
void Josephus(int N, int M){int index = 0;int temp = 0;int num = N; //剩余人数int rem = M; //每次的间距int * a = new int[N];for (int i = 0; i < N; ++i) a[i] = i + 1;bool * Tag = new bool[N];memset(Tag, true, N);for (int i = 0; i < N; ++i) {rem = M % num;//计数循环while (temp < M) {if (Tag[index] == true )++temp;index = (index + 1) % N;}//未被淘汰的第一个while (Tag[index] == false)index = (index + 1) % N;cout << a[index] << " ";Tag[index] = false;--num;temp = 0;//恢复到初始条件}delete[]Tag;}int main(){int N, M;cout << "Please input the number of people N and the gap M: " << endl;cin >> N >> M;Josephus(N, M);system("pause");return 0;}
math:
约瑟夫环问题的简单解法(数学公式法) 点击打开链接
算法的关键就是唯一的那个循环,那个循环是从2个元素开始,因为结合规律已经知道了函数:
f[1]=0;
f[i]=(f[i-1]+m+1)%i; (i>1)
当然我承认我没看懂文章最后的吉大的那个算法,然后自己改了相关的部分,写出了符合本题的代码( 从每次的循环m变为m+1,最后输出的是s+1,自己从头写一次就会找到规律)
f[i]=(f[i-1]+m+1)%i; (i>1)
当然我承认我没看懂文章最后的吉大的那个算法,然后自己改了相关的部分,写出了符合本题的代码( 从每次的循环m变为m+1,最后输出的是s+1,自己从头写一次就会找到规律)
//只能推算最终结果/*原版 从0开始编号,报m-1的被排除f(1)=0 f(n)=[f(n-1)+m]%nint main(){int n, m, i, s = 0;printf("N M = ");cin >> n >> m;for (i = 2; i <= n; i++){s = (s + m) % i;}cout << s ; //编号从0开始system("pause");}*///此时需要从1开始编号了,所以结果+1,报m的排除int main(){int n, m, i, s = 0;printf("N M = ");cin >> n >> m;for (i = 2; i <= n; i++)s = (s + m + 1) % i;cout << s + 1 ; //编号从0开始,但是要求从1system("pause");return 0;}
优点:跑的快,而且线性增长,代码量小
缺点:想不出来,别人想出来,自己需要消化
时间复杂度:
T(N)=O(N^2) 无话可说。。。
阅读全文
0 0
- 约瑟夫问题(Josephus problem)
- 约瑟夫问题(Josephus Problem)
- 约瑟夫问题(Josephus problem)
- 约瑟夫问题(Josephus problem)
- Josephus problem(约瑟夫问题)
- 约瑟夫问题Josephus problem
- 约瑟夫环问题(josephus problem)详解
- Algorithm Gossip: 约瑟夫问题(Josephus Problem)
- 约瑟夫(Josephus problem)环问题初探
- Java-约瑟夫问题(Josephus Problem)
- 关于约瑟夫问题(Josephus Problem)
- 约瑟夫(Josephus)问题
- 约瑟夫(Josephus)问题
- 约瑟夫(Josephus)问题
- 约瑟夫问题(Josephus problem)1:出列的序列
- 约瑟夫问题(Josephus problem)2:某人何时出列
- 约瑟夫问题(Josephus Problem)3:谁最后一个出列
- 约瑟夫问题(Josephus Problem)算法分析及代码
- 关于configure和Makefile
- SSM框架
- 土木工程项目管理系统engineercms
- Socket网络通信
- 编程之美
- 约瑟夫问题(Josephus problem)
- 网络协议关系 及 协议内容
- 欢迎使用CSDN-markdown编辑器
- NOIP2016Day2T2蚯蚓解题报告
- PAT乙级1052. 卖个萌 (20)
- 学习如何使用GitHub
- lucene代码笔记1
- App 到各大应用市场评分
- ajax中的同步异步问题