zoukankan      html  css  js  c++  java
  • [经典算法]约瑟夫问题

    题目说明:

    据说著名犹太历史学家 Josephus有过以下的故事:在罗马人占领乔塔帕特后,39个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人 开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。
    然而Josephus 和他的朋友并不想遵从,Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。

    题目解析:

    约瑟夫问题可用代数分析来求解,将这个问题扩大好了,假设现在您与m个朋友不幸参与了这个游戏,您要如何保护您与您的朋友?只要画两个圆圈就可以让自己与朋友免于死亡游戏,这两个圆圈内圈是排列顺序,而外圈是自杀顺序,如下图所示:

         josephusProblem-1

    使用程式来求解的话,只要将阵列当作环状来处理就可以了,在阵列中由计数1开始,每找到三个无资料区就填入一个计数,直而计数达41为止,然后将阵列由索引1开始列出,就可以得知每个位置的自杀顺序,这就是约瑟夫排列,41个人而报数3的约琴夫排列如下所示:

    14 36 1 38 15 2 24 30 3 16 34 4 25 17 5 40 31 6 18 26 7 37 19 8 35 27 9 20 32 10 41 21 11 28 39 12 22 33 13 29 23

    由上可知,最后一个自杀的是在第31个位置,而倒数第二个自杀的要排在第16个位置,之前的人都死光了,所以他们也就不知道约琴夫与他的朋友并没有遵守游戏规则了。

    程序代码:

    #include <gtest/gtest.h>
    #include <vector>
    using namespace std;
    
    void JosephusCalc(int count, int m, vector<int>& value)
    {
        int nCount = 0;
        int nPos = -1;
        int nIndex = 0;
        char* Status = new char[count];    //状态数组,0表示已经移除,1表示未移除
    
        memset(Status, 1, count * sizeof(char));
        value.clear();
    
        while (nCount < count)
        {
            nPos = (nPos+1) % count;
            nIndex += Status[nPos];
    
            if (nIndex == m)
            {
                value.push_back(nPos+1);
    
                Status[nPos] = 0;
                nCount++;
                nIndex = 0;
            }
        }
        
        delete[] Status;
    }
    
    void ShowResult(const vector<int>& Result)
    {        
        for (int i=0; i<Result.size(); ++i)
        {
            if (i % 10 == 0)
                cout << endl;
    
            cout << Result[i] << " ";        
        }
    }
    
    TEST(Algo, tJosephusProblem)
    {
        vector<int> Result;
        JosephusCalc(41,3,Result);
        ShowResult(Result);
    
        JosephusCalc(6,5,Result);
        ShowResult(Result);
    }
  • 相关阅读:
    how to uninstall devkit
    asp.net中bin目录下的 dll.refresh文件
    查找2个分支的共同父节点
    Three ways to do WCF instance management
    WCF Concurrency (Single, Multiple, and Reentrant) and Throttling
    检查string是否为double
    How to hide TabPage from TabControl
    获取当前系统中的时区
    git svn cygwin_exception
    lodoop打印控制具体解释
  • 原文地址:https://www.cnblogs.com/Quincy/p/4831985.html
Copyright © 2011-2022 走看看