zoukankan      html  css  js  c++  java
  • 约瑟夫问题

      据说著名犹太历史学家 Josephus有过以下的故事:在罗马人占领乔塔帕特后,39 个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。然而Josephus 和他的朋友并不想遵从。首先从一个人开始,越过k-2个人(因为第一个人已经被越过),并杀掉第k个人。接着,再越过k-1个人,并杀掉第k个人。这个过程沿着圆圈一直进行,直到最终只剩下一个人留下,这个人就可以继续活着。问题是,给定了和,一开始要站在什么地方才能避免被处决?Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。

      这个问题是计算机和数学中经典的一个计数问题,在算法的中这种类似的问题被叫做与瑟夫环。

      与瑟夫问题有很多的解决思路,比如最常见的使用循环链表来解决。

      

    #include <stdio.h>
    #include <stdlib.h>
    
    typedef struct node
    {
        int data;
        struct node *next;
    }node;
    
    node *create(int n)
    {
        node *p = NULL, *head;
        head = (node*)malloc(sizeof (node ));
        p = head;
        node *s;
        int i = 1;
    
        if( 0 != n )
        {
            while( i <= n )
            {
                s = (node *)malloc(sizeof (node));
                s->data = i++;    // 为循环链表初始化,第一个结点为1,第二个结点为2。
                p->next = s;
                p = s;
            }
            s->next = head->next;
        }
    
        free(head);
    
        return s->next ;
    }
    
    int main()
    {
        int n = 41;
        int m = 3;
        int i;
        node *p = create(n);
        node *temp;
    
        m %= n;   // m在这里是等于2
    
        while (p != p->next )
        {
            for (i = 1; i < m-1; i++)
            {
                p = p->next ;
            }
    
            printf("%d->", p->next->data );
    
            temp = p->next ;                //删除第m个节点
            p->next = temp->next ;
            free(temp);
    
            p = p->next ;
        }
    
        printf("%d
    ", p->data );
    
        return 0;
    }
    View Code

      我最开始见到这个问题,使用递归来解决这个问题。

    #include<stdio.h>
    
    void
    josephus(int *a,int n, int i)
    {
        int times=1;
        while(number(a,n)>0)
        {
            if(i==n+1)
            {
                i=1;
            }
            while(a[i-1]==0)
            {
                i++;
                if(i==n+1)
                {
                    i=1;
                }
            }
            if(times==3)
            {
                printf("%d->",a[i-1]);
                a[i-1]=0;
                i++;
                josephus(a,n,i);
            }
            times++;
            i++;
        }
    }
    
    int
    number(int *a,int n)
    {
        int i=0;
        int times=0;
        for(i=0;i<n;i++)
        {
            if(a[i]==0)
            {
                ;
            }
            else
            {
                times++;
            }
        }
        return times;
    }
    
    int main()
    {
        int i;
        int n=41;
        int a[n];
        for(i=0;i<41;i++)
        {
            a[i]=i+1;
        }
        josephus(a,n,1);
        printf("
    ");
    }
    View Code

      还可以使用数组模仿循环链表来实现。

    #include<stdio.h>
    #include<malloc.h>
    int main()
    {
        int *person,i,node,n,m;
        scanf("%d%d",&n,&m);
        person=(int*)malloc(sizeof(int)*(n+1));
        for(i=1;i<=n;i++)//初始化圈
        {
            person[i]=i+1;//i表示编号为i的人,person[i]的值表示编号为i的人的下一个人的编号
        }
        person[n]=1;//编号为n的下一个人的编号是1
        node=1;
        while(node!=person[node])//如果某个人的下一个人不是自己,意味着人数超过1人
        {
            for(i=1;i<m-1;i++)//这个循环终止于被杀的人的前一个人
            {
                node=person[node];//下一个人的编号为node,node的值来自于前一个人的person[node]
            }
            printf("%d->",person[node]);//输出被杀的人编号
            person[node]=person[person[node]];//修改被杀的人的前一个人的person[node]为被杀的人的后一个人的编号
            node=person[node];//这句话中的node是被杀的人后一个人
        }
        printf("%d",node);//输出最后幸存者的编号
        printf("
    ");
        return 0;
    }
    View Code
  • 相关阅读:
    浅谈Slick(2)- Slick101:第一个动手尝试的项目
    浅谈Slick(1)- 基本功能描述
    Cats(4)- 叠加Free程序运算结果,Stacking monadic result types
    Cats(3)- freeK-Free编程更轻松,Free programming with freeK
    Cats(2)- Free语法组合,Coproduct-ADT composition
    Cats(1)- 从Free开始,Free cats
    Scalaz(59)- scalaz-stream: fs2-程序并行运算,fs2 running effects in parallel
    Scalaz(58)- scalaz-stream: fs2-并行运算示范,fs2 parallel processing
    Scalaz(57)- scalaz-stream: fs2-多线程编程,fs2 concurrency
    Scalaz(56)- scalaz-stream: fs2-安全运算,fs2 resource safety
  • 原文地址:https://www.cnblogs.com/foreverW/p/7401776.html
Copyright © 2011-2022 走看看