约瑟夫问题(Josephus problem)的一点思考

原创 2007年10月01日 15:54:00
问题的提出:
假设N个人决定选出一个领导,将所有人排成一个圆周,沿着这个圆周每次数M个人就排除对应者,每当有人出列后,剩下的人靠拢,仍然保持一个完整的圆周。问题是找出最后剩下的那个人是谁(根据数学方法,不用这么麻烦,可能早就算出应该是圆周中的哪一个人了)。确定领导的过程是一个N和M的函数,这就是所谓的约瑟夫函数(Josephus  function)。更一般地讲,我们可能希望知道出列人员的顺序。例如,若共有N=9个人,且每数M=5个人就排除对应者,则出列顺序为5  1  7  4  3  6  9  2 ,8为选出的领导。

问题的解答:
问题的解决方式有多种,在此可以构造一个循环链表来解决问题。将N个人按顺序插入一个循环链表,然后从第一个人开始数M个人就删除一个节点,如此往复,直到剩下最后一个节点为止。为此,编写程序如下。
#include <stdlib.h>
#include <stdio.h>

typedef int Item;
typedef struct node *link;
struct node{
    Item item;
    link next;
};

int main(int argc,char *argv[])
{
    int i,N=atoi(argv[1]),M=atoi(argv[2]);
    link t=(link)malloc(sizeof(*t)),x=t;
    t->item=1;t->next=t;
    for(i=2;i<=N;i++){
        x=(x->next=(link)malloc(sizeof(*x)));
        x->item=i;
        x->next=t;
    }
    while(x!=x->next){
        for(i=1;i<M;i++)
            x=x->next;
        x->next=x->next->next;
        N--;
    }
    printf("%d/n",x->item);
    return 0;
}
以上程序的优点在于它能够快速删除节点,若使用数组而不是链表,则会使删除节点的开销增大。使用数组的优点在于它能快速访问数组中任意下标的元素。当我们选择一种数据结构时,必须当心这种选择对算法处理数据的效率的影响。
在C中,指针为链表的抽象概念提供了一种直接而且方便的具体实现,但抽象的基本值并不依赖于任何特定的实现。我们同样可以用整数数组来针对约瑟夫问题实现链表,也就是说,我们可以使用数组索引实现链表,而不是使用指针。下面的表就说明了链表的数组表示方法。具体实现程序有兴趣的话可以编写一下。
链表的数组表示
  0 1 2 3 4 5 6 7 8
item 1 2 3 4 5 6 7 8 9
next 1 2 3 4 5 6 7 8 0

在此,我给出我的实现如下:

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

struct node{
 int item;
 int next;
};

void main(int argc,char *argv[2])
{
 int i,j,N=/*atoi(argv[1])*/9,M=/*atoi(argv[2])*/5;
 // 构造循环链表
 node *t=(node *)malloc(sizeof node *N);
 for(i=0;i<N;i++)
 {
  t[i].next=i+1;
  t[i].item=i+1;
 }
 t[N-1].next=0;
 i=0 ;
 // 模拟选举过程
 while(t[i].next!=i)  /* 该节点的next域不指向自己则继续循环*/
 {
  for(j=0;j<M-2;j++)
   i=t[i].next;
  t[i].next=t[t[i].next].next; /* 将i的next域值设置为其下下个节点的索引*/
  i=t[i].next;     /* 移到下一个节点*/
 }
 printf("%d",t[i].item);
}

当然,这个实现并不是唯一的,我们还可以分别用两个数组来表示,一个Item数组,一个next数组。大小均为N,然后并不修改Item,只修改next。

问题的反思:
算法的灵魂在于思想,不在实现,我们要掌握的是算法本身,而不是程序。程序只是我们算法的实现,不要拘泥于某一特定语言。语言只是工具而已,选用哪种语言,要看我们要解决的问题的规模,复杂度,时间以及空间的要求。当然,我并不是说不用学语言,而只去学数学。我们要学的是将算法的思想用具体的语言工具表达出来,解决实际遇到的问题。
最后,以上纯属本人愚见,不要当真,不同时期,总会有不同的体会,所以,尽情的享受学习带给你的快乐与困苦吧。

约瑟夫问题(Josephus problem)1:出列的序列

版权所有。所有权利保留。 欢迎转载,转载时请注明出处: 约瑟夫问题,又名约瑟夫斯问题(Josephus Problem),描述如下: N个人编号1、2、…、N,围成一圈,从第一个开始报数,第C个将出列...
  • u012077163
  • u012077163
  • 2013年11月18日 22:46
  • 1181

《C++语言基础》实践参考——Josephus(约瑟夫环)问题

返回:贺老师课程教学链接  项目要求【项目-Josephus(约瑟夫环)问题】n个小孩子围成一圈,从第一个小孩子开始顺时针方向数数字,到第m个小孩子离开,这样反反复复,最终只剩下一个小孩子,求第几个小...
  • sxhelijian
  • sxhelijian
  • 2015年05月26日 19:06
  • 4237

约瑟夫环问题(josephus problem)详解

约瑟夫环问题描述:   编号为1,2,3...n的人一词围成一圈,从第k个人开始报数(从1开始),数到m的人退出。接着下一个人又从1开始报数,数到m的人退出,以此类推。问:剩下的人的编号是多少?   ...
  • sun_star1chen
  • sun_star1chen
  • 2013年12月26日 23:11
  • 3402

约瑟夫问题(Josephus_problem) 终极解析

hdu2925   poj 2244 HDU 2211约瑟夫问题数学解法 首先看一看最原始的约瑟夫问题: 1   约瑟夫环(Josephus)问题是由古罗马的史学家约瑟夫(Josephus)...
  • xiangyong58
  • xiangyong58
  • 2014年03月05日 21:04
  • 3519

约瑟夫环问题python解法

约瑟夫环问题:已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到k的那个人被杀掉;他的下一个人又从1开始报数,数到k的那个人又被杀掉;依此规律重复下去,直到...
  • littlethunder
  • littlethunder
  • 2014年09月10日 16:28
  • 7240

算法: 约瑟夫问题(Joseph Problem)的分析

约瑟夫问题(Joseph Problem)的数学解决思路。
  • wlqingwei
  • wlqingwei
  • 2015年03月03日 14:17
  • 2398

Josephus Problem (约瑟夫环数学解法)

约瑟夫环是一个非常经典的数学问题,n个人围成一圈,从1开始报数,每当有人报到m时,他被淘汰,下一个人继续从1开始报数,问最后的获胜者是谁?        有一种很经典的算法是用链表/数组来模拟整个游戏...
  • wchhlbt
  • wchhlbt
  • 2017年03月14日 19:58
  • 865

java数组解决约瑟夫(Josephus)问题

什么是约瑟夫Josephus问题?   假如有M个人,按顺序排成一个圈,编号分别为1-M,现在给一个定数N,从第一个人开始报数,数到第N个人就出列,然后下一个人又从第1开始报数,数到N的人出列。。。...
  • u014401821
  • u014401821
  • 2014年04月18日 08:46
  • 343

Josephus环问题求解(Java实现)

Josephus环问题: 古代某法官要判决number个犯人的死刑,他有一条荒唐的法律,将犯人站成一个圆圈,从第start个人开始数起,每数到第distance个犯人,就拉出来处决,然后再从下一个开...
  • dingjing1994
  • dingjing1994
  • 2017年05月11日 22:37
  • 317

约瑟夫问题Josephus problem

约瑟夫问题:经典算法已知n个人(以编号1,2,3…n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆...
  • FIELDOFFIER
  • FIELDOFFIER
  • 2015年04月25日 17:21
  • 1192
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:约瑟夫问题(Josephus problem)的一点思考
举报原因:
原因补充:

(最多只允许输入30个字)