POJ 1012 Joseph

題目大意:給定一個k,代表有k個好人和k個壞人。按照約瑟夫問題的規則進行。求出最小的m,使經過k輪後,k個壞人全部被殺死。

思路:

(1)先給出約瑟夫環的遞推公式:f(i)=(f(i-1)+m-1)%(n-i+1),f(0)=0;其中n代表開始時共有n人,m代表每次殺死第m個人,f(i)代表按照第i輪順序編號,第i輪應該殺死的人的編號。按照題目要求,好人的編號始終都是0~k-1,所以一旦f(i)<k ,則不符合要求。

(2)遞推公式的證明如下:令第i-1輪殺死的人的編號爲f(i-1),則第i輪從f(i-1)+1開始,此時場上有n-i+1個人。存在映射:

f(i-1) --> 0 ;   f(i-1)+1 --> 1 ;  ......  ;   f(i-1)-2 --> n-i-1 ;   f(i-1)-1 --> n-i;

按照後者的編號,應該殺死的人的編號f ‘(i) = (m-1) % (n-i+1); 則 f(i) = f'(i) + f(i-1)%(n-i+1) = (f(i-1)+m-1)%(n-i+1);

(3)令答案爲m,則m應該大於等於k+1進行枚舉。另外,m不必遞增枚舉,m必須滿足k+1的整數倍或者k+1的整數倍加1。證明如下:考慮第k-1輪時,此時場上還剩下k個好人和1個壞人。此時只存在兩種序列 GGGG.....GGXB 或 GGGG......GGBX,顯然m = t(k+1) + b,t=1,2,3....,b=0或1。

 

代碼,服務器端打表

#include <iostream>
#include <algorithm>

using namespace std;

bool test(int m,int k)
{
    int n=k*2,i,j=0;
    for (i=1;i<=k;i++)
    {
        j=(j+m-1)%(n-i+1);
        if (j<k)
            return false;
    }
    return true;
}

int main()
{
    int k,ans[14],j;
    for (k=1;k<=13;k++)
    {
        for (j=1;;j++)
        {
            if (test(j*(k+1),k))
            {
                ans[k]=j*(k+1);
                break;
            }
            if (test(j*(k+1)+1,k))
            {
                ans[k]=j*(k+1)+1;
                break;
            }
        }
    }
    while (scanf("%d",&k)==1 && k!=0)
        printf("%d\n",ans[k]);
    return 0;
}



 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章