Sequential Nim(CodeForces - 1382B)【博弈】

B - Sequential Nim (CodeForces - 1382B)

題目連接ios

算法

博弈c++

時間複雜度O(N)算法

1.這道題乍一看覺得用Nim博弈直接套用就能夠了,結果經過題意發現並非。題目中要求取石子時只能從下標最小的那一堆開始取,也就是說一堆一堆的取,不能跳着取。spa

2.分析完題意,咱們知道最後取完最後一堆的人必勝。那麼怎麼分析誰最後會贏呢?.net

若是隻有一堆的話,很容易得出第一我的獲勝。關鍵在於如何分析多堆的狀況。code

爲了方便,咱們將每一堆中首先取的人稱爲先手,而後取的人是後手,下面咱們來進行分類討論:blog

  • 若是某一堆只有1個石子,那麼先手只能取這一個石子。若是還有剩餘的石堆,那麼此先手在下一堆中將成爲後手(由於兩我的是輪流取的);若是沒有剩餘的石堆,那麼此先手獲勝。
  • 若是某一堆中有若干個石子(超過1個),爲了最優,先手有兩種取法,要麼全取完,要麼取走大部分,只剩餘一個。前者會使得先手在下一堆中充當後手,後者會使先手在下一堆中充當先手。固然若是沒有下一堆了,取完便可,這時先手贏。不然還要繼續判斷。

分類討論後發現,一共就上面兩大類狀況。那麼該怎麼作呢?這裏是題目的一個難點。ci

對於先手,當該石堆中石子個數超過1而且還有其餘的石堆時,他能夠根據實際狀況選擇在下一堆中成爲先手仍是後手。可是當石堆中石子個數爲1時他別無選擇,只能是在下一堆中成爲後手。因此說石子個數爲1的石堆爲轉折點。get

既然當某石堆石子個數大於1時先手能夠任意選擇在下一堆中他的身份,因此若是還有其餘石堆,那麼該先手必勝。(由於他掌握着主動權,因此他徹底能夠根據剩餘的石堆數來選擇接下來的身份,至於怎麼選咱們不用考慮)io

當石子個數等於1時,先手變成後手,後手變成先手。

3.總結一下,咱們只需從頭判斷每一堆的石子的個數,若個數爲1,則繼續循環,直到循環完。若是循環完了,說明都爲1,這時只需判斷石堆個數便可;若出現個數不爲1的,則先手必勝,跳出循環便可。

C++代碼

#include<iostream>
using namespace std;
const int N = 1e5 + 10;
int t, n;
int a[N];
int main()
{
    cin >> t;
    while(t--)
    {
        cin >> n;
        for(int i = 0; i < n; i++)
            cin >> a[i];
        int first = 1, second = 0;
        bool flag = false;
        for(int i = 0; i < n; i++)
        {
            if(a[i] == 1)
            {
                if(first)
                {
                    first = 0;
                    second = 1;
                }
                else
                {
                    first = 1;
                    second = 0;
                }
            }
            else
            {
                if(first)
                    puts("First");
                else
                    puts("Second");
                flag = true;
                break;
            }
        }
        if(!flag)
        {
            if(n % 2 == 1) puts("First");
            else puts("Second");
        }

    }
}

思路來源(注意這裏「先手」的定義與思路來源鏈接裏的「先手"定義不一樣)

相關文章
相關標籤/搜索