约瑟夫环问题
约约瑟夫
无是用
是用数都有一个共同点:要模整个约约约约约约约约约约约约约约约约约约约约约约约约约约约
游程,不程序写起来比,而且度高达约约约约约约约约约约约约约约约约约约约约约约约约O(nm),当n,m非常大(例如上百万,上千万)约约约约约约约约约约约约约约约约约约约约约的候,几乎是没有法在短内出果的。我
约约约约约约约约约约约约约约约约约约约约约约约约注意到原是要求出最后的利者的序号,而不是要
者模整个程。因此如果要追求效率,就要打破常,施一点数学策略。约约约约约约约约约约约约约约约约约约约约约约约约约约约约约约约约约约约约约约约约约约约约约约约约约约约约约约约约了方便,先把稍微改一下,并不影响原意:
约约描述:n约约个人,号0~(n-1)),从0约约约约约约始数,到(m-1)约约约的退出,剩下的人从0约始数。求利者的号。约约约约约约约约约约约
我知道第一个人约约约约约约约(约号一定是m%n-1) 出列之后,剩下的n-1约约约约约约个人成了一个新的瑟夫,以号约约约约约约约约约k=m%n约约约的人始,:
k k+1 k+2 ... n-2, n-1, 0, 1, 2, ... k-2并且从k约约始0。
约约约约约约约约约约约约约约在我把他的号做一下:
k --> 0
k+1 --> 1
k+2 --> 2
...
...
k-2 --> n-2
k-1 --> n-1
约约约约后就完完全全成了(n-1)约约约约约约约约约约约约约约约约约约约约约约约个人数的子,假如我知道个子的解:例如x是最的利者,那根据上面个表把个约约约约约约约约约约约约约约约约约约x约约约约约回去不好就是n约约约个人情况的解,::约约约约约约约约约约约约约约约回去的公式很,相信大家都可以推出来:x'=(x+k)%n如何知道(n-1)约约约约约约约约约约约约约约个人数的的解,,只要知道(n-2)个人的解就行了。(n-2)个人的解呢,当然是先求(n-3) 的情况---- 约约约约约约约约约约约约约约然就是一个倒推:好了,思路出来了,下面写推公式:约约约约约
令f[i]表示i约约个人玩游m约约约约约约约约约约约约约约约退出最后利者的号,最后的果自然是f[n]约推公式
f[1]=0;
f[i]=(f[i-1]+m)%i; (i>1)
有了个公式,我要做的就是从约约约约约约约约约约约约约1-n约序算出f[i]约约约约约约约的数,最后果是f[n]约约约约。因生活中号是从约约约约约1约约约约始,我出f[n]+1
由于是逐推,不需要保存约约约个每f[i]约约约,程序也是异常:
#include
int main(){
int n, m, i, s=0;
printf ("N M = "); scanf("%d%d", &n, &m);
for (i=2; i<=n; i++) s=(s+m)%i;
printf ("The winner is %d\n", s+1);}
约约约约约约约个算法的度O(n)约约约约约约约约约约约约约约约约约,相于模算法已有了很大的提高。算n,m等于一百万,
一千万的情况不是了。可,适当地运用数学策略,不可约约约约约约约约约约约约约约约约约约约约以程得,而且往往会成倍地提高算法行效率。约约约约约约约约约约约约约约约约约约约约约约约约约 int josefus(int n,int m) {
int l=0,c;
for(c=1;c<=n;c++)
l=(l+m-1)%c+1;
return l;
}
问问,问瑟夫问
有问号从1到N的N个数人坐成一圈问~问到M的人出局~下一位再从1问始~
如此持问~直止剩下一位问止~问告此人的问号X。问入N,M~求出X。问瑟夫问算法(循问问表解决).问在老问出的问问是那问....... 呵呵
java问问:
public class Josephus {
public static void main(String[] args) {
if(args.length<2){
System.out.println("Input N and M.");
return;
}
int n = Integer.parseInt(args[0]);
int m = Integer.parseInt(args[1]);
int point=0,number=1;
List list = new ArrayList();
for(int i=1;i<=n; i++){
//初始化问表
list.add(i);
}
while(list.size()>1){
if(number%m==0){
list.remove(point);
--point;
}
++point;//指问后移
++number;
if(point>list.size()-1){
//指问越界重新问始
point=0;
}
}
System.out.println(list.get(0));
}
}
c问问:
•#include
•#include
struct node
{
int v;
struct node *next;
}*p,*head,h; //head是问指问~h是问问点
main()
{
int n,m;
int i;
puts("问问入人数n和问上限数m :");
scanf("%d%d",&n,&m);
h.next=NULL; //问问点的next问空
head=&h; //问指问指向问问点
p=head; //p也指向问问点
/*下面的循问用建立循问问表来*/
for(i=1;i<=n;i++)
{
p->next=(struct node*)malloc(sizeof(struct node));
p=p->next;
p->v=i;
if(i!=n)
{
p->next=NULL;
}
else
{
p->next=head->next;
}
}
p=head;
p=p->next; //p指向第一问点个
m%=n;//当m>n问有用
while(p!=p->next)
{
for(i=1;i<=m-2;i++)
{
p=p->next;
}
printf("%d ",p->next->v);
p->next=p->next->next;
p=p->next;
}
printf("%d",p->v);
}
1 #include
2 #include
3 //约约约约约约约约约约约约约约约约约约约瑟夫的:一群人成一圈,群人共有 n个人,个人身上都一个每key,依次约
约约约约圈人号:
4 //1,2,n 一始数的上限约约约约约约约约约m从第一个人,号:约约约1,自一始数到约约约约约约m约约约停止数,
约到m的人出列,
5 //将他的密做新的约约约约约m约约约约约约约约约约约约约约约约约,从他的方向始的下个人始从新从一数,如此下去,直至所有的人出列止约约约约约约约约约约约约约约约约约约
6 typedef struct Node
7 {
8 int key;//每个人身上的约约key
9 int NUM;//每个人的号约约
10 struct Node *next;
11 }Node;
12 //=========================
13 int n;//约共的人数
14 Node *L=NULL;//循表指约约约约约
15 //=========================
16 void InitList(int x)//初始化第一个点,个点有的意约约约约约约约约约约约约约
17 {
18
19 L = (Node*)malloc(sizeof(Node));
20 if(!L)
21 {
22 printf("malloc fail\n");
23 system("PAUSE");
24 exit(1);
25 }
26 L->NUM=1;
27 L->key=x;
28 L->next=L;
29 }
30 //===========================================
31 void DelNode(Node *p_front)//p_front指向的是p的前一个点,除的却是约约约约约约约约p
32
33 {
34 Node *tmp=p_front->next;
35 p_front->next = tmp->next;
36 free(tmp);
37 }
38 //============================================
39 void CreateList(void)//约约约约建循表
40 {
41 printf("Players n=");
42 scanf("%d",&n);
43 while(n<1||n>30)
44 {
45 printf("n must >=1 && <=30\n");
46 printf("Players n=");
47 scanf("%d",&n);
48 }
49 int key_tmp;
50 printf("NUM=1 key=");
51 scanf("%d",&key_tmp);
52 while(key_tmp<1||key_tmp>300)
53 {
54 printf("key must >0&&<=300\n");
55 printf("NUM=1 key=");
56 scanf("%d",&key_tmp);
57 }
58 InitList(key_tmp);
59 int i;
60 Node *s,*p=L;
61 for( i=2;i<=n;i++)
62 {
63 s=(Node*)malloc(sizeof(Node));
64 if(!s)
65 {
66 printf("malloc error\n");
67 system("PAUSE");
68 exit(1);
69 }
70 printf("NUM=%d key=",i);
71 scanf("%d",&key_tmp);
72 while(key_tmp<1||key_tmp>300)
73 {
74 printf("key must >0 && <=300");
75 printf("\nNUM=%d key=",i);
76 scanf("%d",&key_tmp);
77 }
78 s->key=key_tmp;
79 s->next=L;//构成循表的约约约约next指约约约
80 p->next=s;
81 s->NUM=i;
82 p=s;//指约p往前移 约
83 }
84 }
85 //=============================================
86 void PlayGame(void)//约约约约约始游:数
87 {
88 Node *p=L;
89 Node *p_front=L;
90 int m;
91 printf("start game !\n");
92 printf("m=");
93 scanf("%d",&m);
94 while(m<1||m>300)
95 {
96 printf("m must >0 && <=300\n m=");
97 scanf("%d",&m);
98 }
99 int i;
100 int count = n;
101 for(i=1;i<=m;i++)
102 {
103 // printf("num =%d key=%d\n",p->NUM,p->key);
104
105 if(m==i)
106 {
107
108 m=p->key;
109 i=0;
110 printf(" %d",p->NUM);111 DelNode(p_front); 112 p=p_front;
113 count--;
114 if(count==1)
115 {
116 printf(" %d",p->NUM);
117 //printf("num =%d key=%d\n",p->NUM,p->key);
118 printf(" all out !\n");
119 system("PAUSE");
120 exit(0);
121 }
122
123 }
124 p_front=p;
125 p=p->next;
126
127 }
128 }
129 //==============================================
====
130 int main(int argc, char *argv[])//运行游:约约
131 {
132 CreateList();
133 PlayGame();
134 system("PAUSE");
135 return 0;
136 }
137
是一的问用问问, 个数学
已知n个号人;以问1~2~3...n分问表示,问坐在一问问周问。问问问桌从号k的人问始问数~数到m的那人出列~他的下一人又个个从1问始问~到数数m的那人又出列~依此问律个
重问下去~直到问周问的人全部出列。 桌
例如,n = 9, k = 1, m = 5
【解答】
出局人的问序问5, 1, 7, 4, 3, 6, 9, 2, 8。
问表方法
问就是问瑟夫问问问的问问问景~有一问是要通问问入个n,m,k三正整~求出列的序列个数来。
问问问采用的是典型的循问问表的据问~就是一问表的尾元素指问指向问首元素。 个数构将个p-
>link=head
解问问的核心步问,;程序的基本算法, 决
1.建立一具有个n个问问点~无问问点的循问问表~ 2.确定第1个数问问人的位置~
3.不地问表中问除问问点~直到问表问空。 断从
void JOSEPHUS(int n,int k,int m) //n问问人~数k问第一问始问的人~个数m问出列者
喊到的 数
{
/* p问前问点 当r问问助问点~指向p的前问问点 list问问问点*/
LinkList p,r,list; /*建立循问问表*/
for(int i=0,idata=i;
if(list==NULL)
list=p;
else
r->link=p;
r=p;
}
p->link=list; /*使问表循问起来*/
p=list; /*使p指向问问点*/
/*把前指问移问到第一问问的人当个数*/ for(i=0;ilink;
}
/*循问地问除问列问点*/
while(p->link!=p) {
for(i=0;ilink;
}
r->link=p->link;
printf("被问除的元素,%4d ",p->data);
free(p);
p=r->link;
}
printf("\n最后被问除的元素是,,4d",P->data);
}
Josephus(问瑟夫)问问的非问问方法
首先我问列出一些有问问瑟夫问的问果,
1 1 2 2 3 2 4 1 5 4 6 1 7 4 8 7 9 1 10 4
11 7 12 10 13 13 14 2 15 5 16 8 17 11 18 14 19 17 20 2021 2 22 5 23 8 24 11
25 14 26 17 27 20 28 23 29 26 30 29
31 1 32 4 33 7 34 10 35 13 36 16 37 19 38 22 39 25 40 28 41 31 42 34 43 37 44 40 45 43 46 46 47 2 48 5 49 8 50 11 51 14 52 17 53 20 54 23 55 26 56 29 57 32 58 35 59 38 60 41 61 44 62 47 63 50 64 53 65 56 66 59 67 62 68 65 69 68 70 171 4 72 7 73 10
74 13 75 16 76 19 77 22 78 25 79 28 80 31
81 34 82 37 83 40 84 43 85 46 86 49 87 52 88 55 89 58 90 61 91 64 92 67 93 70 94 73 95 76 96 79 97 82 98 85 99 88 100 91 意思是~前一问问瑟夫问的人~后一问最后出去的人的问。 个数数个数号
上面的表中我问可以问问出以下问问, 从两个
问问1:若上一问字问最后保留比人少一~问下一数号数数从1问始问。
问问2:若上一问字问最后保留人相等~问下一数号与数数从2问始问。
以下是C问言问的程序。 写
#include
#define M 200
int main()
{
int temp=0;
int b=1,k=0;
for(int i=1;i<=M;i++)
{
temp=b+3*k;
if(i==temp)//问问1:若上一问字问最后保留比人少一~问下一数号数数从1问始问。
{
b=2;
k=0;
continue;
}
else if(i-temp==1)//问问2:若上一问字问最后保留人相等~问下一数号与数数从2问始问。
{
b=1;
k=0;
continue;
}
k++;
}
printf("%d %d ",M,temp); return 0;
}
Josephus(问瑟夫)问问的方法数学
无问是用问表问问问是用问问问都有一共同点,要模问整游问问程~不问程序起比问问数个个写来~
而且问问问问度高达O(nm)~当n~m非常大(例如上百万~上千万)的问候~乎是有问法几没在短问问出问果的。我问注意到原问问问问是要求出最后的问利者的序~而不是要问者模问整内号
个数学问程。因此如果要追求效率~就要打破常问~问施一点策略。 问了问问方便~先把问问稍微改问一下~不影原意, 并响
问问描述,n个号人;问0~(n-1))~从0问始问~问到数(m-1)的退出 ~剩下的人问问从0问始问。求问利者的问。 数号
我问知道第一人个(问一定是号(m-1)%n) 出列之后~剩下的n-1个个人问成了一新的问
瑟夫问;以问问号k=m%n的人问始,:
k k+1 k+2 ... n-2, n-1, 0, 1, 2, ... k-2
且并从k问始问0。
问在我问把他问的问做一下问问, 号
k --> 0
k+1 --> 1
k+2 --> 2
...
...
k-3 --> n-3
k-2 --> n-2
序列1, 1, 2, 3, 4, …, n-2, n-1, n
序列2, 1, 2, 3, 4, … k-1, k+1, …, n-2, n-1, n 序列3, k+1, k+2, k+3, …, n-2, n-1, n, 1, 2, 3,…, k-2, k-1
序列4,1, 2, 3, 4, …, 5, 6, 7, 8, …, n-2, n-1 问问后就完完全全成问了(n-1)个数个人问的子问问~假如我问知道问子问问的解,例如x是最问的问利者~那问根据上面问表把问个个x问回去
问好就是n个况很来人情的解问,,,问回去的公式问问~相信大家都可以推出, ? k=m%n;
? x' = x+k = x+ m%n ; 而 x+ m%n 可能大于n
?x'= (x+ m%n)%n = (x+m)%n
得到 x‘=(x+m)%n
如何知道(n-1)个数人问的问问的解,问~只要知道(n-2)个人的解就行了。(n-2)个人的解,然是先求呢当(n-3)的情 况---- 问问然就是一倒推问问,好了~思路出了~下面问个来写
推公式,
令f表示i个人玩游问问m退出最后问利者的问~最后的问果自然是号f[n]. 问推公式:
f[1]=0;
f=(f[i-1]+m)%i; (i>1)
有了问公式~我问要做的就是个从1-n问序算出f的问~最后问果是数f[n]。因问问问生活中问问是号从1问始~我问问出f[n]+1由于是逐问问推~不需要保存每个f~程序也是常问问,异 #include
int main(void)
{
int n, m, i, s=0;
printf ("N M = ");
scanf("%d%d", &n, &m);
for (i=2; i<=n; i++)
s=(s+m)%i;
printf ("The winner is %d\n", s+1); return 0 ;
}
问算法的问问问问度问个O(n)~相问于模问算法已问有了大的提高。算很n~m等于一百万~一千万的情不是问问了。可问~适地用策略~不问可以问问程问得问问~而且往往况当运数学会
成倍地提高算法问行效率。
照上面提供的思路~我问问可以问似的得到一更易于明白的方法~问有;参个1,2,3~……~k-1~k~k+1~……~n,n个数当~k出列问~那问有
k+1 -->1
k+2 -->2
...
...
n -->n-k
1 -->n-k+1
...
...
k-1 -->n-1
由上面一问式子可以推出~若知道新问生的n-1个数个数中某x~那问问然可以推出很
x在原列里的位置~数即x‘=;x+k,%n,由此~我问可以得到一问推公式 个
f[1]=1
f[n]=(f[n-1]+k)%n ;n>1,
如果问问上式可以推出问瑟夫问问问的解~不幸~问了~上面的问推公式中~在某问你很你
情下~况f[n-1]+k会整除n~如n=2~k=3~问问我问修要问上式问行修正~
f[n]=(f[n-1]+k)%n;if(f[n]==0)f[n]=n;
问问得解。 程序代问如下,
#include int main()
{
int n,k,s=1;
scanf("%d%d",&n,&k); for(i=2;i<=n;i+=1) {
s=(s+k)%i;
if(s==0)s=i;
}
printf("ans=%d\n",s); return 0;
}
然~我问问可以用当问问方法解此问问, 决
#include int main()
{
int jos(int n,int k); int n,k,s;
scanf("%d%d",&n,&k); s=jos(n,k);
printf("ans=%d\n",s); return 0;
}
int jos(int n,int k) {
int x;
if(n==1)x=1;
else {x=(jos(n-1,k)+k)%n;if(x==0)x=n;}
return x;
}
解决Josephus(问瑟夫)问问的pascal代问 program Josephus(input,output);
type pointer=^nodetype; nodetype=record
data:integer;
link:pointer
end;
var head,next,last:pointer;
i,n,s,j,m,k:integer; begin
writeln('问问入问成问瑟夫问的人,数'); read(n);
new(head);
head^.data :=1;
last:=head;
for i:=2 to n do begin
new(next);
next^.data :=i;
last^.link :=next; last:=next
end;
last^.link :=head; next:=head;
repeat
begin
writeln(next^.data ); next:=next^.link end;
until next=head; readln;
next:=head;
writeln('问问入第一问问人的位置个数:'); read(s);
j:=1;
if s<=n
then
while jnext do
begin
k:=1;
while k #define M 10/*问人数*/
#define N 5
#define START 0/*第一问问的人个数*/ void main(void)
{
int a[M],i=0,k,count=0;
while(i++M-1)
t=i-1,i=0;
printf("%d ",i?a[i-1]:a[M-1]); a[(i?(i-1):(M-1))]=0;
}
getch();
}