zoukankan      html  css  js  c++  java
  • 约瑟夫斯环 (减治法)

    题目:

    约瑟夫斯是一位著名的犹太历史学家,参加并记录了公园66~70年犹太人反抗罗马的起义。约瑟夫斯作为一个将军,设法守住裘达波特的堡垒47天,但在城市陷落之后,他和40名顽强的将士在一个洞穴中避难。在哪里,叛乱者表示“要投降毋宁死”。于是约瑟夫斯建议每个人应该轮流杀死他旁边的人,而这个顺序抽签决定。约瑟有预谋的拿到了最后一签,成为了幸存者。

    我们让n个人围成一个圈,并编号1~n,从编号1的人开始计数,每次消去第二个人,知道留下最后幸存者。这个问题要求出幸存者的号码J(n)。如果n=6,第一轮,2、4、6位置上的人被杀,然后3,5补刀2,3的位置上,第二轮1、3被杀,5幸存下来。J(6)=5;如果n=7,第一轮,2,4,6,1被杀,第二轮3,5被杀,J(7)=7;

    算法分析:

    将人数分为基数n,偶数n考虑。如果n为偶数,n=2k,一轮之后,规模减半。3到了2个位置,5到了3的位置,7到了4的位置。为了得到一个人的初始位置,需要将他的新位置x2-1,对于幸运者这个关系会一直持续下去:

    J(2K)=2J(K)-1

    对于基数n,n=2k+1,第一轮会消去所有偶数位的人,同时把位置1的人消去,留下了一个规模为k的例子,新位置编号和旧位置之间的关系为:

    J(2K+1)=2J(K)+1

    为了得到这2个递推式的闭合式,一般反向替换法,还可以用前向替换法,比如求出J(N)的前15个值,用数学归纳法证明合理性。而在这个案例中,规模n刚好可以用2进制表示:我们可以对n本身做一次向左的循环唯一来得到J(n)。如J(6)=J(110)(2进制)=101(2进制向左移位)=5,J(7)=J(111)(2进制)=111(2进制移位后)=7。

    在网上看了下还有,对于移动位数不确定的情况,可以用循环链表实现。附上代码

    #include<iostream>
    #include<list>
    #include<cstdlib>
    using namespace std;
     
    int main(int argc, char* argv[])
    {  
        int total=0;  
        cout<<"Please input the total num:";  
        cin>>total;    
        int keyNum=0;  
        cout<<"Please input the key num:";  
        cin>>keyNum;    
        if(keyNum<keyNum || keyNum<1 || total<1)  
        {   
            cout<<"input error!"<<endl;   
            system("paused");  
        }    
          
        list<int>* table=new list<int>();    
        for(int i=1; i<=total; ++i)  
        {   
            table->push_back(i);  
        }    
          
         int shout=1;    
         for(list<int>::iterator it=table->begin(); table->size()!=1;)  
         {   
             if(shout++==keyNum)   
             {    
                 //cout<<*it<<endl;    
                 it=table->erase(it);    
                 shout=1;    
             }   
             else   
             {    
                 ++it;   
             }      
              
             if(it==table->end())   
             {    
                 it=table->begin();   
             }  
         }    
         cout<<"The last one is:";   
         cout<<*table->begin()<<endl;    
         system("pause");  
         return 0; 
     }
  • 相关阅读:
    date format记录
    python同时遍历两个list
    Windbg分析DMP文件
    DNS原理及其解析过程(转)
    有关正则表达式的详细内容
    sizeof _countof _tcslen的比较
    关于androidX
    UML类图
    springBoot 访问html页面遇到的坑
    hashmap 的实现原理
  • 原文地址:https://www.cnblogs.com/SeekHit/p/4912273.html
Copyright © 2011-2022 走看看