5-28 猴子选大王 (20分)
一群猴子要选新猴王。新猴王的选择方法是:让N只候选猴子围成一圈,从某位置起顺序编号为1~N号。从第1号开始报数,每轮从1报到3,凡报到3的猴子即退出圈子,接着又从紧邻的下一只猴子开始同样的报数。如此不断循环,最后剩下的一只猴子就选为猴王。请问是原来第几号猴子当选猴王?
输入格式:
输入在一行中给一个正整数N(≤1000)。
输出格式:
在一行中输出当选猴王的编号。
输入样例:
11
输出样例:
7
约瑟夫问题(猴子选大王)
#include <stdio.h>
#include <stdlib.h>
/* 定义链表节点类型 */
typedef struct node
{
int data;
struct node *next;
}linklist;
int main()
{
int i, n, k, m, total;
linklist *head, *p, *s, *q;
/* 读入问题条件 */
printf("请输入猴子的个数:");
scanf("%d", &n);
printf("请输入要从第几个猴子开始报数:");
scanf("%d", &k);
printf("请输入出局数字:");
scanf("%d", &m);
/* 创建循环链表,头节点也存信息 */
head = (linklist*) malloc(sizeof(linklist));
p = head;
p->data = 1;
p->next = p;
/* 初始化循环链表 */
for (i = 2; i <= n; i++)
{
s = (linklist*) malloc(sizeof(linklist));
s->data = i;
s->next = p->next;
p->next = s;
p = p->next;
}
/* 找到第 k 个节点 */
p = head;
for (i = 1; i < k; i++)
{
p = p->next;
}
/* 保存节点总数 */
total = n;
printf("\n出局序列为:");
q = head;
/* 只剩一个节点时停止循环 */
while (total != 1)
{
/* 报数过程,p指向要删除的节点 */
for (i = 1; i < m; i++)
{
p = p->next;
}
/* 打印要删除的节点序号 */
printf("[%d] ", p->data);
/* q 指向 p 节点的前驱 */
while (q->next != p)
{
q = q->next;
}
/* 删除 p 节点 */
q->next = p->next;
/* 保存被删除节点指针 */
s = p;
/* p 指向被删除节点的后继 */
p = p->next;
/* 释放被删除的节点 */
free(s);
/* 节点个数减一 */
total--;
}
/* 打印最后剩下的节点序号 */
printf("\n\n猴子大王为第 [%d] 号\n\n", p->data);
free(p);
//system("pause");
return 0;
}
方法二(我个人比较喜欢的)
#include <stdio.h>
#include <stdlib.h>
int main()
{
int n,i,a[1000],count=0,num,q=0;
scanf("%d",&n);
for(i=0;i<n;i++){
a[i]=i+1;
}
while(q<n){
for(i=0;i<n;i++){
if(a[i]!=0){
count++;
num=i+1;
}
if(count==3){
count=0;
a[i]=0;
q++;
}
}
}
printf("%d",num);
return 0;
}