POJ 1012 Joseph 題解

POJ 1012 Joseph 題解

題目解讀:

The Joseph’s problem is notoriously known. For those who are not familiar with the original problem: from among n people, numbered 1, 2, …, n, standing in circle every mth is going to be executed and only the life of the last remaining person will be saved. Joseph was smart enough to choose the position of the last remaining person, thus saving his life to give us the message about the incident. For example when n = 6 and m = 5 then the people will be executed in the order 5, 4, 6, 2, 3 and 1 will be saved.
Suppose that there are k good guys and k bad guys. In the circle the first k are good guys and the last k bad guys. You have to determine such minimal m that all the bad guys will be executed before the first good guy.

本道題目的背景是約瑟夫環問題。約瑟夫環是一個數學的應用問題:已知n個人(以編號1,2,3,4…n分別表示)圍坐在一張圓桌周圍。從編號爲k的人開始報數,數到m的那個人出列;他的下一個人又從1開始報數,數到m的那個人又出列;依次規律重複下去,直到圓桌周圍的人全部出列。通常解決這類問題時我們把編號從0—n-1,最後結果+1即爲原問題的解。
在本道題中對約瑟夫環問題作了一個簡單的變形,通過求解最小的報數m,來使得所有的bad guy先於good guy被淘汰。

解決算法

我們在這裏假設環的編號從0開始,以下的計算與公式推導均滿足這一點。
注意觀察到報數m具有延續性,對於n個人而言,第一輪約瑟夫環淘汰了一個人後,剩下的n-1個人其實又組成了一個新的約瑟夫環,唯一區別的就是兩個約瑟夫環中的成員編號是不同的。因此,我們可以理解爲這裏需要解決的是不同編號序列之間的一個映射關係,即將第i+1輪中被淘汰的人的編號映射到第i輪中對應的編號序列。這與動態規劃思想中狀態轉移的思想有相近的地方,因此考慮使用DP算法。現在先給出狀態轉移方程:

ans[0]=0

ans[i]=(ans[i1]+m1)/(ni+1)i>=1

遞歸公式推導:
假設有n個人,且報數確定爲m。當第一輪編號爲m-1(也就是第m個人,這裏有一個轉換關係)的人出來之後,新的約瑟夫環即需要從第m+1個人起重新編號,這個時候就有新的編號映射關係爲:

第i個人 原來的編號 新的編號
(m+1)%n ((m+1)%n-1)%n 0
(m+2)%n ((m+1)%n-1)%n 1
…… …… ……

設n個人圍成一個圈的時候被淘汰的是X號,n-1個人圍成一個圈的時候被淘汰的是Y號,此處假設Y已經被求出來:
Y=(X*n+n-m)%n
則可以得到反推式:
X=(Y+m-1)%n

代碼:

#include<iostream>
#include<vector>

using namespace std;

int final[14]={0};

int Joseph(int k)
{
    int result[14];
    int i,m,n,label=0;
    n=2*k;
    result[0]=0;          //第0輪無淘汰的對象
    m=k+1;                //初始化m
    while(true){
        for(i=1;i<=k;i++){    //前k輪需要被淘汰的序號,這裏的序號編號從0開始
            result[i]=(result[i-1]+m-1)%(n-i+1);
            if(result[i]<k){
                label = -1;
                break;
            }
        }
        if(label==-1){
            m++;
            label=0;
        }
        else{
            break;
        }
    }
    return m;
}

int main()
{
    vector<int> input;
    vector<int> output;
    int num=0;
    int k;
    cin>>k;
    while(k!=0){
        input.push_back(k);
        num++;
        cin>>k;
    }
    for(int i=0;i<num;i++){
        if(final[input[i]]!=0){
            output.push_back(final[input[i]]);
        }
        else{
            final[input[i]]=Joseph(input[i]);
            output.push_back(final[input[i]]);
        }
    }
    for(int i=0;i<num;i++){
        cout<<output[i]<<endl;
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章