您的位置:首页 > 其它

有关约瑟夫问题小结

2015-05-13 12:07 260 查看
<span style="font-family: Verdana, Arial, 'BitStream vera Sans', Helvetica, sans-serif;"></span>
循环链表有个典型应用就是解约瑟夫问题(Josephus),这里用的典型题目是"猴子选大王"。

问题描述:有m只猴子打算从中选出一个大王,但猴子们打斗三日,仍然选不出大王。后来经过协商,决定选大王的规则如下: 大家围成一圈,从1到m为每次猴子编号。然后从1开始报数, 数到n的出局。剩下的猴子再从1开始报数。最后剩下来的就是大王。有一只猴子很聪明(它就是猴精!)占据了一个位置,最后成为了大王。请编程计算一下,它占据是的哪个位置。
输入格式:一行,由空格分开的两个整数m n。
输出格式:一个整数,表示大王的编号
样例输入:15 3   样例输出:5
样例输入:200 55   样例输出:93
数据规模和约定:10000>m>0; 100>n>0;


C语言代码如下:
<span style="font-family: Verdana, Arial, 'BitStream vera Sans', Helvetica, sans-serif;">//</span>
//  main.c
//  main
//
//  Created by Apple on 15/5/13.
//  Copyright (c) 2015年 Apple. All rights reserved.
//

#include <stdio.h>

int main(int argc, const char * argv[]) {
int a[10000];
int m;
int n;
int x;
int count;
int i;
scanf("%d",&m);
scanf("%d",&n);
for(i=1;i<=m;i++)
a[i]=i;
count=m;
x=0;
for(i=0;count>1;i++){
if(a[i%m+1]!=-1){
x++;
}
if(x==n && a[i%m+1]!=-1){
a[i%m+1]=-1;
count--;
x=0;
}
}
for(i=1;i<=m;i++)
if(a[i]!=-1)
printf("%d\n",i);
return 0;
}


循环链表c语言实现:

//
//  main.c
//  main2
//
//  Created by Apple on 15/5/13.
//  Copyright (c) 2015年 Apple. All rights reserved.
//

#include <stdio.h>
#include <stdlib.h>

/* 定义链表节点类型 */
typedef struct node{
int data;
struct node *next;
}linklist;

int main(int argc, const char * argv[]) {
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;
}

只用数组方法:

//
//  main.c
//  main4
//
//  Created by Apple on 15/5/13.
//  Copyright (c) 2015年 Apple. All rights reserved.
//

#include <stdio.h>
int choose(int n,int m);
int n,m;  /*n只猴子,报数m*/
int a[10000];

int main(int argc, const char * argv[]) {
int m,n,p;
scanf("%d %d",&n,&m);
p=choose(n,m);
printf("%d",p);
getchar();
return 0;
}

int choose(int n,int m){
int i,sum=0,countOne=n; /*存剩余猴子数*/
for(i=0;i<n;i++)
a[i]=1;
i=0;

while (i<=n){
if (i==n) i=0; /*当i=n时,循环回去*/
sum+=a[i];
if(sum==m) /*当报到m时  */{
sum=a[i]=0;  /*淘汰倒霉猴子;即赋0 */
countOne--; /*剩余猴子数-1*/
if (countOne==1)
break; /*剩1只时结束*/
}
i++;
}

for(i=0;i<n;i++){
if(a[i]!=0)
return i+1; /*找到猴子大王编号(从1开始的)*/
}
return 0;
}

最后一个算法是在网上看到的,我表示并不能看懂是什么意思,先放在这里吧。如果有哪个大神看懂了记得跟我讲解一下

//
// main.c
// main3
//
// Created by Apple on 15/5/13.
// Copyright (c) 2015年 Apple. All rights reserved.
//

#include <stdio.h>
const int M = 3;

int main(int argc, const char * argv[]) {
int n, s = 0;
scanf("%d", &n);
int i;
for (i = 2; i <= n; ++i)
s = (s+M)%i;
printf("%d\n", s+1);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: