您的位置:首页 > 其它

(算法)约瑟夫环问题

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

思路:假如有7个人,围成一圈,从某个人开始编号0到6,从编号为0的人开始数1到3,数到3的人出列,下一个人又从1开始数到3,数到3的人又出列,知道最后一个人为止,我们写一下过程,用编号来表示:

一:0、1、2、3、4、5、6(数到3,编号2出列,然后从编号3开始);

二:3、4、5、6、0、1(数到3,编号5出列,然后从编号6开始);

三:6、0、1、3、4(数到3,编号1出列,然后从编号3开始);

四:3、4、6、0(数到3,编号6出列,然后从编号0开始);

五:0、3、4(数到3,编号4出列,然后从编号0开始);

六:0、3(数到3,编号0出列,然后从编号3开始);

七:3(显然最后是编号3出列)。

上面的思路分析重要的一点是这些人是围成一圈的,即编号是循环来数的,从哪个编号开始是无关重要的,取决于你从哪个人开始编号,从哪个编号开始数,博主上面写的这七个编号写成一排,每一趟的起始点可能不一样,符合循环次序就好,这只是便于分析,我们可以用一个数组来存这些编号,然后通过操作数组来得到我们想要的结果,上面每一趟的变化我们可以用简单的c代码来表示(我们使用了两个数组:int a[7],int b[7],一开始初始化它们的内容相同,数组a的循环内容变化通过b[(i + 3) % n]来操作):

while(n > 1)
{
for(i = 0;i < n - 1;i++)
{
a[i] = b[(i + 3) % n];
}
for(i = 0;i < n - 1;i++)
{
b[i] = a[i];
}
n--;
}


我们推广到一般情形,它有n个人,围成一圈,从0到n-1编号,并从编号k开始数1到m,数到m的人出列,下一个人又从1开始数,数到m的人又出列,直到最后一个人出列,每一趟变化用c代码表示为:

while(n > 1)
{
for(i = 0;i < n - 1;i++)
{
a[(i + k) % (n - 1)] = b[(i + k + m) % n];
}
for(i = 0;i < n - 1;i++)
{
b[i] = a[i];
}
n--;
}


下面就是博主用c语言写的完整程序:

#include<stdio.h>
int fun(int a[],int b[],int n,int m,int k);
int main(void)
{
int i,n,m,k;
int a[10],b[10];
printf("请您输入总共的人数(n):");
scanf("%d",&n);
printf("让这%d个人围成一圈,从0到%d来编号,。\n",n,n-1);
printf("请您输入k的值,让%d个编号从k编号开始数:",n);
scanf("%d",&k);
printf("从编号%d开始,1开始数,数到m,然后去除数到m的编号,接着让下一个输入从1开始报数直到m就去除该编号,请您输入m的值:",k);
scanf("%d",&m);
for(i = 0;i < n;i++)
{
a[i] = i;
b[i] = i;
}
printf("最后剩下的编号是:");
printf("%d",fun(a,b,n,m,k));
return 0;
}

int fun(int a[],int b[],int n,int m,int k)
{
int i;
while(n > 1) { for(i = 0;i < n - 1;i++) { a[(i + k) % (n - 1)] = b[(i + k + m) % n]; } for(i = 0;i < n - 1;i++) { b[i] = a[i]; } n--; }
return a[0];
}


以上是博主的分享,谢谢各位读者的浏览!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: