解法一:利用一个循环链表,节点的data域存储整数1至n,每次遍历m步,把第m个节点删除,如此循环下去,直至只剩一个节点,(只剩一个节点的判断方法是:节点的指向节点自己,也就是p->next=p),节点的data域就是最后那个人的编号
#include <iostream>
#include <string>
#include <vector>
#include <string.h>
#include <algorithm>
#include <stack>
using namespace std;
typedef struct node
{
int data;
node *next;
}LNode,* LinkList;
void create(LinkList *l, int n)//创建循环链表
{
LinkList head;
*l = (LinkList)malloc(sizeof(LNode));
(*l)->data=1;
(*l)->next=NULL;
head = (*l);
for(int i=2;i<=n;i++)
{
LinkList p;
p = (LNode*)malloc(sizeof(LNode));
p->data=i;
(*l)->next=p;
(*l)=p;
}
(*l)->next=head;
(*l)=head;
}
void joseph(int n,int m,LinkList l)
{
LinkList p,q;
p=l;
while(p->next!=p)
{
for(int i=1;i<m-1;i++)
{
p=p->next;
}//p指向被删除元素的前一个结点
q=p->next;//q指向被删除元素
p->next=q->next;
p=q->next;//p指向下一个开始位置
free(q);
}
printf("%d\n",p->data);
}
int main(int argc, char *argv[])
{
int n,m;
while(cin >> n >> m,n!=0&&m!=0)
{
if(m==1)
{
printf("%d\n",n);
}//m等于1时候是特殊情况
else
{
LinkList list;
create(&list,n);
joseph(n,m,list);
}
}
return 0;
}
解法二:递归。考虑第一次删除,第m个猴子出队后,第m+1个猴子喊1,m+2喊2,。。。第n个猴子喊n-m。第一个猴子喊n-m+1。那么这就变成了一个n-1个猴子报数为m的约瑟夫问题,而且这里最后剩下人就是原来编号为x的那个人,按前面的对应关系f(n)=(f(n-1)+m)%n。另外的技巧是将猴子编号为0到n-1,关系重新定义为f(n)=(f(n-1)-1+m)%n+1
#include <iostream>
#include <stdio.h>
#include <algorithm>
using namespace std;
int joseph(int m,int n)
{
if(n==2)
{
if(m%2==0)
return 1;
else
return 2;
}
else if(n>2)
{
return (joseph(m,n-1)-1+m)%n+1;
}
}
int main()
{
int mm,nn;
while(cin >> nn >> mm,mm!=0&&nn!=0)
{
if(nn==1)
printf("%d\n",1);
else
printf("%d\n",joseph(mm,nn));
}
return 0;
}