POJ_1781_In Danger_約瑟夫問題

這道題是約瑟夫問題的變形,大意就是給定很多人,圍成一個環,從一開始數,每次殺死第三人,事實上按數據是每數到2就殺死當前的人。第一個樣例中,一共五人,先殺死2號,之後是4號,然後1號,最後殺死5號,於是3號最後活下來了。

輸入數據,讀爲字符型較方便,我是直接讀一個字符串s,然後計算人數人數,這個人數很多,模擬的話一定會超時,但是模擬的方法先簡述一下:

設有n個人,數到m殺死當前人。

定義一個布爾型數組記錄人的生死,初始化爲true,代表都活着。定義一個k=0,記錄已經殺死幾個人。一個變量t記錄當前人的編號,x記錄數到了幾。

當k不等於n時,t每次加一,若t大於n;則令t=1。若通過布爾型數組判斷編號爲t的人還活着,x也加一。若x==m,令數組下標爲t的值爲false。那麼最後的t值即爲活下來的人。

核心代碼(模擬):

memset (a,true,sizeof(a));
        s=0,t=0,k=0;
        do
        {
            t++;
            if (t>n)
                t=1;
            if (a[t]==true)
                s++;
            if (s==m)
            {
                a[t]=false;
                s=0;
                k++;
                if(k==n)
                    cout<<t<<endl;
            }
        }while (k!=n);

然而對於這道題,需要找到一些規律,否則會超時。

那麼假設n個人,每次殺死第m人時活下來的是編號爲k的人,當m一定,對於n+1個人來說,第一個殺死的是編號爲m的人,還剩下n人,那麼這就和n個人的情況一樣了,只是不是從第一個人開始數,而是從m+1開始。這樣有n+1個人時,最終活下來的爲第k+m號人。同理,n+2時,爲k+2m號。

問題是k每次加m時,n只是加上1,可能會出現算出的活下來的人的編號大於n的情況,此時怎麼辦呢?顯然,我們對算出的數對n取模即可。

這時對本題中m一直爲2,對於n爲2的整數次冪時,第一次轉一圈殺死了所有的編號爲偶數的人,然後又從1號開始,這時剩下n/2個人,人數還是2的整數次冪,不妨把這些人重新按順序編號,又殺死了那些編號爲偶數的一半人,依然回到1……最後顯然回到n=2的情況,最終活下來的人爲1號。所以,當n爲2的整數次冪時,活下來的人是1號。

這樣對於一個任意的n,若是2的整數次冪答案爲1,。其他的只要找到不大於它的最大的2的整數次冪的數x,然後算出1+2(n-x)即爲答案。那麼關於這個值爲什麼必然小於下一個2的整數次冪數,下一個數爲2x,n-x>x時,n>2x,不大於n的最大的2的整數次冪的數就是2x了。

AC代碼

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
long long p;
int n,m,z;
string s;
long long ef[50]={0,1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768,65536,131072,262144,524288,1048576,2097152,4194304,8388608,16777216,33554432,67108864,134217728,268435456};
//數組打表記錄2的整數次冪
int main()
{
    while (cin>>s,s[0]-'0'+s[1]-'0')
    {
        n=s[0]-'0';
        m=s[1]-'0';
        z=s[3]-'0';
        p=(n*10+m);
        for (int i=1;i<=z;i++)
            p*=10;
        if (p==1||p==2||p==4)
        {
            cout<<1<<endl;
        }
        else
        {
            if (p==3)
                cout<<3<<endl;
            else
            {
                long long t;
                int k;
                for (int i=1;p>ef[i];i++)
                    k=i;
                if (ef[k+1]==p)
                    cout<<1<<endl;
                else
                {
                    t=1+2*(p-ef[k]);
                    cout<<t<<endl;
                }       
            }   
        }       
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章