解题思路:本题可以使用链表模拟猴子报数,这一方法具有较高的效率并且易于理解。大致方法是构成一个链表环,表头指针跟着计数值共同变化,等计数值等于报数值时进行删除操作。但是用链表做题一定要注意题目有一特殊情况,即m==1时,因为链表中的判断及处理都是在前一个节点进行,因而m==1是该方法的一处死角,一定要做特殊化的处理!其次,链表的使用中有不少的细节需要我们留意,可以关注一下代码中的注释部分。
总时间限制:
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
#include<stdio.h>
struct Monkey
{
int ID;
Monkey *next;
};
int main()
{
Monkey *link,*tail,*monkey;
int n,stride,count;
while(scanf("%d%d",&n,&stride)!=EOF)
{
if(n==0&&stride==0)
break;
if(stride==1) //链表做这题一定要考虑这种情况,算是个大坑!
{
printf("%d\n",n);
continue;
}
link=tail=NULL;
for(int i=1;i<=n;i++)
{
monkey=new Monkey;
monkey->ID=i;
if(tail==NULL)
{
link=tail=monkey;
}
else
{
tail->next=monkey; //此处设置正确的指针指向。
tail=monkey;
}
}
tail->next=link;
count=1;
while(link!=NULL)
{
if(link->next==link)
{
printf("%d\n",link->ID);
delete link; //删除最后一处链表空间。
break;
}
if(count==stride-1) //这里一定要注意,因为使用的是链表格式,所以这里的count数数为stride-1时就要停下进行处理,因为必须在前一个节点进行处理!
{
monkey=link->next;
link->next=monkey->next; //这一句将该节点从链表中删除。
//printf("%d ",monkey->ID);
delete monkey; //使用链表一定要删除相应的空间。
count=0;
}
count++;
link=link->next;
}
}
return 0;
}