http://bailian.openjudge.cn/practice/2746/
2746:约瑟夫问题
-
总时间限制:
- 1000ms 内存限制:
- 65536kB
-
描述
-
约瑟夫问题:有n只猴子,按顺时针方向围成一圈选大王(编号从1到n),从第1号开始报数,一直数到m,数到m的猴子退出圈外,剩下的猴子再接着从1开始报数。就这样,直到圈内只剩下一只猴子时,这个猴子就是猴王,编程求输入n,m后,输出最后猴王的编号。
输入
-
每行是用空格分开的两个整数,第一个是 n, 第二个是 m ( 0 < m,n <=300)。最后一行是:
0 0
-
输出
对于每行输入数据(最后一行除外),输出数据也是一行,即最后猴王的编号
样例输入
-
6 2 12 4 8 3 0 0
样例输出
-
5 1 7
-
//这是我已开始写的,模拟整个过程,后来发现还有个递推式
令f表示i个人玩游戏报m退出最后胜利者的编号,最后的结果自然是f[n]递推公式f[1]=0;f=(f+m) mod i; (i>1)有了这个公式,我们要做的就是从1-n顺序算出f的数值,最后结果是f[n]。因为实际生活中编号总是从1开始,我们输出f[n]+1由于是逐级递推,不需要保存每个f,程序也是异常简单: -
//这里利用了循环的一个式子i=(i+1)%N 但i要从0开始 #include <cstdio> #include <cstring> bool sign[330]; int main() { int i,j; int N,M; while(scanf("%d%d",&N,&M),M+N) { memset(sign,1,sizeof(sign)); j=0; for(i=1;i<N;++i) { int cnt=0; while(cnt!=M) { if(sign[j]) cnt++; if(cnt==M) sign[j]=0; j=(j+1)%N; } } for(int i=0;i<N;++i) { if(sign[i]) printf("%d\n",i+1); } } return 0; }
-
-
#include <cstdio> #include <cstring> int cal(int n,int m) { int s=0; for(int i=2;i<=n;i++) s=(s+m)%i;//如果s从1开始,则(s+m-1)%i+1 return s; } int main() { int n,m; while(scanf("%d%d",&n,&m),m+n) { printf("%d\n",cal(n,m)+1); } }