1. 程式人生 > >猴子選大王(3種超簡單的方法)

猴子選大王(3種超簡單的方法)

17個猴子圍成一圈,從某個開始報數1-2-3-1-2-3-……報“3”的猴子就被淘汰,遊戲一直進行到圈內只剩一隻猴子它就是猴大王了。

方法一:
小技巧:用陣列來記錄猴子是否在圈內的狀態:在圈內記為“1”,不在圈內記為“0”。並以累加陣列元素值來模擬報數過程,這樣就減少了判斷猴子是否在圈內的操作。
C++程式碼如下:

#include <iostream>
#include <vector>
using namespace std;

const int N = 17;

//列印N只猴子的狀態(“1”表示在圈內,“0”表示不在圈內)
void printVec(const
vector<int> &v) { for (vector<int>::const_iterator it = v.begin();it != v.end();++it) { cout<<*it<<' '; } cout<<endl; } int monkeyKing(vector<int> v) { //n記錄還有多少隻猴子在圈內 int n = N; int k = 0; int i; while (n > 1) { for
(i=0;i<N;++i) { k += v[i]; if (k == 3) { v[i] = 0; printVec(v); k = 0; --n; } } } //最後一隻猴子下標為1 for (int i=0;i<N;++i) { if (1 == v[i]) return
i+1; } } int main() { vector<int> v(N,1); cout<<"猴大王是第"<<monkeyKing(v)<<"只."<<endl; return 0; }

執行結果:
這裡寫圖片描述

方法二:
方法一的缺點是每次都要掃描包括已出圈的所有猴子,時間效率比較低。而如果用陣列元素來儲存其下一隻在圈內猴子的下標,就能方便地找到下一隻在圈內猴子。當一個猴子的下一隻猴子就是自己時,圈內就只剩一隻猴子,它就是候大王了。
C++程式碼:

#include <iostream>
#include <vector>
using namespace std;

const int N = 17;

int main()
{
    vector<int> v(N,0);
    for (int i=0;i<N-1;++i)
    {
        v[i] = i+1;
    }
    int test = 0;
    int last;
    while(test != v[test])
    {
        for (int i=0;i<3;++i)
        {
            last = v[test];
            test = v[last];
            cout<<"第"<<test+1<<"只猴子報3"<<endl;
            v[last] = v[test];
            test = v[test];
        }
    }
    cout<<"猴大王是第"<<test+1<<"只."<<endl;
    return 0;
}

執行結果:
這裡寫圖片描述

updata 2016.07.16
方法3:
在n(0、1、2、3、……、n-1)只猴子中,假定報數m的猴子被刪除,則第一隻被刪除的猴子編號為(m-1)%n,記為k,那麼刪除k之後剩下的n-1只猴子為0、1、……、k-1、k+1、……、n-1,並且下一次是從k+1開始計數。相當於在剩下的序列種,k+1排在最前面,從而形成k+1、……、n-1、0、1、……、k-1。接下來將剩下的這n-1個數字的序列k+1、……、n-1、0、1、……、k-1對映形成一個從0到n-2的序列0、1、2、……、n-2。把對映定義為p,則p(x)=(x-k-1)%n。逆過來0、1、2、……、n-2對映為k+1、……、n-1、0、1、……、k-1,時則p’(x)=(x+k+1)%n,而k=(m-1)%n,故p’(x)=(x+m)%n。最後一隻猴子的編號為0,故x=0,n=1。例如當m=3時,p’(0)=(0+3)%1=3,表示最後一隻猴大王在倒數第二輪(編號也是從0開始)中編號為3。
下面給出C++程式碼:

#include <iostream>

using namespace std;
//n只猴子,報數m的被刪掉
int LastRemaining(unsigned int n, unsigned int m)
{
    if (n<1 || m<1) return -1;
    //last表示最後一隻猴子(猴大王)在每輪(先倒數第1輪,再求倒數第二輪,...)中自己的序號
    //倒數第一輪時只有一隻猴子(猴大王),編號為0
    int last = 0;
    //i表示倒數第i次排序
    for (int i=2;i<=n;++i)
    {
        last = (last+m)%i;
    }
    return last+1;//+1為符合習慣,表示將編號變成從1開始
}

int main()
{
    cout<<LastRemaining(17, 3)<<endl;
    return 0;
}