经典约瑟夫问题:
题目描述
已知 n 个人(编号分别为 1、2、3,……、n)围坐在一张圆桌周围,从编号为 1 的人开始报数,数到 m 的那个人出列;他的下一个人又从 1 开始报数,数到 m 的那个人又出列,依次规律重复下去,直到圆桌周围的人全部出列
输入描述
一行:人数 n 和间隔数 m,均不大于 100。
输出描述
出列顺序,每个编号之间用一个空格分开
样例输入
9 5
样例输出
5 1 7 4 3 6 9 2 8
约瑟夫问题的关键在于如何实现循环,对于这类问题,使用数组实现固然可行,通过设一个变量start实现对起始位置的标记,再通过取余实现循环。但是通过C++STL库中的list循环链表解题更直观,下面是实现代码:
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n,m;
while(cin>>n>>m){
list<int>l;
for(int i=1;i<=n;i++) l.push_back(i);
int cnt=0;
while(l.size()!=1){
int node=l.front();
l.pop_front();
cnt++;
if(cnt%m==0){
cout<<node<<" ";
continue;
}
l.push_back(node);
}
cout<<l.front()<<endl;
}
return 0;
}
下面这题坏人必须死则是约瑟夫问题的变种:
有 m 个好人和 m 个坏人坐成一个圈,前 m 个人是好人(编号为 1,2,3...,m) , 后 m 个人是坏人(编号为 m+1,m+2,...,2m). 现在他们开始循环报数,要求从编号为 11 的人开始报,如果有人报到 k 则他必须死亡,而死掉的人的下一个人则继续从 11 开始报数。请求出最小的 k 使得,所有的坏人都死掉而好人都活下来.
输入描述
多组输入,每组输入 1 行,为一个整数 m (1≤m≤12)
输出描述
对于每组输入,输出为 1个整数 k 为使得坏人都死掉的最小报的数
样例输入
Copy to Clipboard
3 4
样例输出
Copy to Clipboard
5 30
#include<bits/stdc++.h>
using namespace std;
int main()
{
int m;
while(cin>>m){
int total=2*m,re=total,start=1,next,h=0;
int k=m+1;
while(h!=m){
next=start+k-1;
next%=re;
if(next>m||next==0){
h++;
if(h==m)cout<<k<<endl;
re--;
if(next==0)start=1;
else start=next;
}else{
re=total;
start=1;
h=0;
k++;
}
}
}
return 0;
}
这题我并未使用链表而是通过取余模拟实现过程,也是比较好理解的。
约瑟夫问题比较简单,重要的是其中的思想,多多训练,只有熟悉简单问题的解决方法,才能在解决复杂问题时游刃有余。