約瑟夫(Josephus problem)環問題初探

HFUT_Uzi發表於2017-04-27

問題描述:N個人依次圍成一個圈,從1~N編號,從1號開始報數,報到M的人自殺(最後一個人不用自殺),問自殺順序以及誰是勝利者

演算法:

兩種方法:一種是用計算機模擬遊戲的執行過程,一種是直接推演出數學規律。這裡只討論前一種

陣列模擬

用一維陣列來表示這N個人的集合,由於非動態陣列無法模擬現實中的集合將某一個元素清理出集合,所以可以用一個額外的狀態標識陣列來記錄某個人是否已經自殺;雖然動態陣列模擬的集合可以將元素清理出去,但時間複雜度為O(N),所以不考慮這種方法。

演算法描述

/*
1、初始化編號陣列,狀態陣列
2、repeat until 還剩下不止一個人{
    定位編號,修改狀態;
}
*/
void Josephus( int M, int N )
{
    //初始化陣列
    int * Jose = (int*)malloc( sizeof( int ) * N );
    bool * JoseTag = (bool*)malloc( sizeof( bool ) * N );

    for( int i = 0; i < N; i++ ) {
        Jose[i] = i + 1;
        JoseTag[i] = true;
    }

    //模擬遊戲進行
    int start = 0;      //每次報數時開始的下標{start|start belong to 0:N-1}
    int end;            //結束報數時的下標
    //int delta = 0;        //報了多少個數
    int count = N;      //還剩多少個人

    while( count != 1 ) {   //還未決出勝負
        end = start;
        int delta = 0;
        while( delta < M ) {    //要經過M個活人
            end = (end + 1) % N;
            if( JoseTag[end] == true )
                delta++;
        }

        JoseTag[end] = false;
        start = (end + 1) % N;  
        while( JoseTag[start] == false )    //當前編號的人必須是活人
            start = (start + 1) % N;

        printf( "%d\t", Jose[end] );

        count--;
    }

    printf( "\n%d is the victor!\n", Jose[start] );
    free( Jose );
    free( JoseTag );
}

單迴圈連結串列模擬

/*
話不多說:直接建立一個單迴圈連結串列,模擬刪除即可
*/
void Josephus( int  M, int N )
{
    List Head = (List)malloc( sizeof( Node ) );
    List Rear = Head;
    Head->next = NULL;

    for( int i = 0; i < N; i++ ) {
        List S = (List)malloc( sizeof( Node ) );
        S->number = i + 1;
        Rear->next = S;
        Rear = S;
        Rear->next = NULL;
    }

    Rear->next = Head->next;
    free( Head );

    List Start = Rear;
    int count = N;
    while( count != 1 ) {
        for( int i = 0; i < M; ++i ) {
            Start = Start->next;
        }
        List Temp = Start->next;
        Start->next = Temp->next;
        printf( "%d\t", Temp->number );
        free( Temp );
        count--;
    }
    printf( "\n%d is the victor!\n", Start->number );
    free( Start );
}

相關文章