约瑟夫环

来源:互联网 发布:淘宝运费险理赔价格表 编辑:程序博客网 时间:2024/05/29 08:36

约瑟夫环

约瑟夫环(约瑟夫问题)是一个数学的应用问题:已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依规律重复下去,直到圆桌周围的人全部出列。通常解决这类问题时我们把编号从0~n-1,最后结果+1即为原问题的解。


C语言

递归法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
#include<stdio.h>
#include<stdlib.h>
struct_Node
{
intdata;
struct_Node*next;
};
typedefstruct_Nodenode_t;
typedefstruct_Linklist
{
node_t*phead;
node_t*ptail;
intlen;
}Linklist;
staticnode_t*GetNode(inti)//新建并初始化节点
{
node_t*pNode;
pNode=(node_t*)malloc(sizeof(node_t));
if(!pNode)
{
printf("Error,thememoryisnotenough!\n");
exit(-1);
}
pNode->data=i;
pNode->next=NULL;
returnpNode;
}
voidinit_list(Linklist*plist)//用第一个节点初始化循环单链表
{
node_t*p;
p=GetNode(1);
//printf("TheNewNodeis:%d\n",p->data);//****TEST****
plist->phead=p;
plist->ptail=p;
p->next=plist->phead;
plist->len=1;
}
staticvoidCreate_List(Linklist*plist,intn)//把其余数据添加到循环单链表中
{
inti=0;
node_t*pNew;
for(i=2;i<=n;i++)
{
pNew=GetNode(i);
/********TEST********
printf("TheNewNodeis:%d\n",pNew->data);
********TEST********/
plist->ptail->next=pNew;
plist->ptail=pNew;
pNew->next=plist->phead;
plist->len++;
}
printf("Completesthee-waycirculationchaintablethefoundation!\n");
}
voidPrint_List(Linklist*plist)//输出链表内容
{
node_t*pCur=plist->phead;
do
{
printf("The%dperson.\n",pCur->data);
pCur=pCur->next;
}while(pCur!=plist->phead);
printf("ThelengthoftheList:%d\n",plist->len);
}
 
约瑟夫回环函数实现
 
voidjoseph(Linklist*plist,intm)//约瑟夫回环函数实现
{
node_t*pPre=plist->ptail;
node_t*pCur=plist->phead;
inti;
while(plist->len!=1)
{
i=0;
while(i<m-1)
{
pPre=pPre->next;
i++;
}
pCur=pPre->next;
pPre->next=pCur->next;
free(pCur);
plist->len--;
}
printf("Thelastoneis:%d\n",pPre->data);
}
intmain()
{
intn=0;
printf("PleaseinputtheLengthoftheCirclelist:");
scanf("%d",&n);
intm=0;
printf("PleaseinputtheStoppoint:");
scanf("%d",&m);
LinklistpList;
init_list(&pList);
Create_List(&pList,n);
Print_List(&pList);
joseph(&pList,m);
return0;
}

  

  
非递归法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include<stdio.h>
#defineM200
intmain
inttemp=0;
intb=1,k=0;
for(inti=1;i<=M;i++)
temp=b+3*k;
if(i==temp)//规则2:若上一组数字为最后保留号与人数相等,则下一数从2开始记。
b=2;
k=0;
continue;
elseif(i-temp==1)//规则1:若上一组数字为最后保留号比人数少一,则下一数从1开始记。
{b=1;k=0;continue;}
k++;
printf("%d%d",M,temp);
return0;
 
【PHP模拟】
 
php有非常完善的数据结构模拟方案,可以非常简洁的解决这样的问题.
当然数量级太大那还是使用数学方法吧!$m>$n的情况也能行,想优化效率不知道该怎么写了.请大神补充吧!
functionking($n,$m){
$monkey=range(1,$n);//模拟建立一个连续数组
$i=0;
while(count($monkey)>1){
$i+=1;//开始查数
$head=array_shift($monkey);//直接一个一个出列最前面的猴子
if($i%$m!=0){
array_push($monkey,$head);//如果没数到m或m的倍数,则把该猴放回尾部去.
}//否则就抛弃掉了
}
return$monkey[0];
}
echo'剩余',king(3,4),'号猴子';

0 0
原创粉丝点击