您的位置:首页 > 其它

poj-约瑟夫问题(猴子选大王)

2013-08-29 20:16 246 查看

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


解题报告:

本题可以用模拟的方法,可以用数组或者是链表解决,用链表的话会更方便些,在这里只介绍下用数组的方法好了,新手比较容易理解。

用houzi[MAX]数组来存放n个数,相当于n个数排成的圈;划掉一个数的操作,就用将一个数组元素置为0的方法来实现。人工数的时候,要跳过已经划掉的数,那么程序执行的时候,就要跳过为0的数组元素。需要注意的是,当 i 指向houzi中最后一个元素(下标n-1)时,要回到第一个元素,这样houzi才像一个圈。

参考程序1:
#include<stdio.h>
#define MAX 300
int main()
{
	int houzi[MAX+10],n,m;
	int i;
	int count,sum;		//sum记录猴子总数,count记录当前数到的猴子数

	while(scanf("%d%d",&n,&m)&&(n||m))
	{
	for(i=0;i<n;i++)
		houzi[i]=i+1;//数组赋值
	i=0;		//从第一只猴子开始
	sum=n;		
	while(sum>1)	//当猴子总数超过1时继续操作
	{	count=0;
		while(count<m)
		{
				
			if(i>=n)
				i%=n;	//下标,当i大于n-1时,回到起点
			if(houzi[i])	//如果猴子未出圈,则数进去
				count++;
			i++;
		
		}
		if(i-1<0)	//注意下标,当数到第n-1只猴子时,下标i会变为0,i-1小于0
			houzi[n-1]=0; //于是第n-1只猴子出圈而不是第i-1只,因为i-1<0
		else
			houzi[i-1]=0;
		sum--;  	//出圈一只,则猴子总数减一

	}
	for(i=0;i<n;i++)	//找到没出圈的那只猴子,输出下标
		if(houzi[i])
		{
			printf("%d\n",i+1);
			break;
		}
	}
	return 0;
}


参考程序2:用数组aloop来存放n个数,用变量nptr指向当前数到的数组元素
#include<stdio.h>
#define N 300
int main()
{
	int nloop[N+10],nptr,count;
	int n,m,i;
	while(1){
	scanf("%d%d",&n,&m);
	if(n==0)
		break;
	for(i=0;i<n;i++)
		nloop[i]=i+1;
	nptr=0;
	for(i=0;i<n;i++) //每次循环将1只猴子赶出圈子,最后被赶出的是猴王
	{	
		count=0; //记录本轮数到的猴子数
		while(count<m)//一直数出m个猴子
		{
			while(nloop[nptr]==0)	//跳过已经出圈的猴子
				nptr=(nptr+1)%n;//到下一个位置
			count++;		//数到一只
			nptr=(nptr+1)%n;	//到下一个位置
		}
		nptr--;				//还需回退一个位置
		if(nptr<0)			
			nptr=n-1;
		if(i==n-1)			//最后一直出圈的猴子
		{
			printf("%d\n",nloop[nptr]);
		}
		nloop[nptr]=0;			//猴子出圈
	}
	}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: