问题描述:
约瑟夫问题:有n只猴子,按顺时针方向围成一圈选大王(编号从1到n),从第1号开始报数,一直数到m,数到m的猴子退出圈外,剩下的猴子再接着从1开始报数。就这样,直到圈内只剩下一只猴子时,这个猴子就是猴王,编程求输入n,m后,输出最后猴王的编号。
输入输出要求:
输入:需能同时输入多组数据,以0 0结尾标志着结束。
样例输入:6 2 12 4 8 3 0 0
样例输出:5 1 7
解决思路:
1.由于猴子围成了一个圈,故此处使用循环链表的数据结构,将每只猴子看作是一个结点,用序号表示。
//建立结点数据结构
typedef struct node
{
int data;
struct node *next;
}Node,*Link;
for(i=0;i<n;i++)//尾插法生成循环链表
{
p = (Link)malloc(sizeof(Node));
p->data = i+1;
tail->next = p;
p->next = head->next;
tail = p;
}
2.当猴子报数为m时,将该猴子所表示的结点删除,并将下一个结点(猴子)标号为1,看作是下一趟报数的起点。
if(i==m)
{
q->next = p->next;
free(p);
p = q->next;
i = 1;//第二趟报数
}
3.如果不是m号猴子,不改变结点,指针指向下一结点。
代码实现:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//建立结点数据结构
typedef struct node
{
int data;
struct node *next;
}Node,*Link;
int main()
{
int n,m,count,i;
//定义头结点head
Link head,tail,p,q;
head = (Link)malloc(sizeof(Node));
head->next = NULL;
while(1)
{
scanf("%d %d",&n,&m);
if(n==0&&m==0)//结束条件
{
free(head);
break;
}
else
{
tail = head;
for(i=0;i<n;i++)//尾插法生成循环链表
{
p = (Link)malloc(sizeof(Node));
p->data = i+1;
tail->next = p;
p->next = head->next;
tail = p;
}
p = head->next;//p指向第一个结点
q = tail;//q指向最后一个结点
i = 1;
while(p!=q)//出列
{
if(i==m)
{
q->next = p->next;
free(p);
p = q->next;
i = 1;//第二趟报数
}
else//q指针在p指针之前,如果两个指针重合,说明只剩下一个结点
{
q = p;
p = p->next;
i++;
}
}
printf("%d\n",p->data);
free(p);
}
}
return 0;
}