ACM-约瑟夫问题

来源:互联网 发布:淘宝卖家心酸 编辑:程序博客网 时间:2024/04/19 16:29

问题描述

        约瑟夫问题:有n只猴子,按顺时针方向围成一圈选大王(编号从1到n),从第1号开始报数,一直数到m,数到m的猴子退出圈外,剩下的猴子再接着从 1 开始报数。就这样,直到圈内只剩下一只猴子时,这个猴子就是猴王,编程求输入n,m后,输出最后猴王的编号。

输入数据

       每行是用空格分开的两个整数,第一个是 n, 第二个是 m ( 0 < m, n < 300)。最后一行是:
       0 0

输出要求

       对于每行输入数据(最后一行除外),输出数据也是一行,即最后猴王的编号

输入样例

6 212 48 30 0

输出样例

517

解题思路

        初一看,很可能想把这道题目当作数学题来做,即认为结果也许会是以 n 和 m 为自变量的某个函数 f(n,m),只要发现这个函数,问题就迎刃而解。实际上,这样的函数很难找,甚至也许根本就不存在。用人工解决的办法就是将 n 个数写在纸上排成一圈,然后从 1 开始数,每数到第 m 个就划掉一个数,一遍遍做下去,直到剩下最后一个。有了计算机,这项工作做起来就会快多了,我们只要编写一个程序,模拟人工操作的过程就可以了。
        用数组 anLoop 来存放 n 个数,相当于 n 个数排成的圈;用整型变量 nPtr 指向当前数到的数组元素,相当于人的手指;划掉一个数的操作,就用将一个数组元素置 0 的方法来实现。人工数的时候,要跳过已经被划掉的数,那么程序执行的时候,就要跳过为 0 的数组元素。需要注意的是,当 nPtr 指向 anLoop 中最后一个元素(下标 n-1)时,再数下一个,则nPtr 要指回到数组的头一个元素(下标 0),这样 anLoop 才象一个圈。

参考程序

#include <iostream>using namespace std;#define MAX_NUM 300int aLoop[MAX_NUM+10]; int main(){int n,m,i;while(true){cin>>n>>m;if(!n && !m){break;}for(i=0;i<n;i++){aLoop[i] = i+1;}int nPtr = 0;//每次循环将 1 个猴子全赶出圈子,最后被赶出的就是猴王for(i=0;i<n;i++){int nCounted = 0;while(nCounted < m){//数出 m 个猴子while(aLoop[nPtr] == 0){//跳过已经出圈的猴子nPtr = (nPtr + 1)%n;//到下一个位置}nCounted++;//找到一只猴子nPtr = (nPtr + 1)%n;//到下一个位置}nPtr--;//上面最后因为到了下一位置,所以这里要回退一个位置if(nPtr < 0){nPtr = n-1;}if(i == n-1){//最后一只出圈的猴子cout<<aLoop[nPtr]<<endl;}aLoop[nPtr]=0; //猴子出圈}}return 0;}


0 0
原创粉丝点击