1. 程式人生 > >hihocode #1172 : 博弈遊戲·Nim遊戲·二

hihocode #1172 : 博弈遊戲·Nim遊戲·二

時間限制:10000ms單點時限:1000ms記憶體限制:256MB

描述

Alice和Bob這一次準備玩一個關於硬幣的遊戲:
N枚硬幣排成一列,有的正面朝上,有的背面朝上,從左到右依次編號為1..N。現在兩人輪流翻硬幣,每次只能將一枚正面朝上的硬幣翻過來,並且可以隨自己的意願,在一枚硬幣翻轉後決定要不要將該硬幣左邊的任意一枚硬幣也翻一次(正面翻到背面或背面翻到正面)。翻最後一枚正面向上的硬幣的人獲勝。同樣的,這次遊戲裡面Alice仍然先手,兩人均採取最優的策略,對於給定的初始局面,Alice會獲勝還是Bob會獲勝?

輸入

第1行:1個正整數N,表示硬幣數量。1≤N≤10,000
第2行:1個字串,第i個字元表示編號為i的硬幣狀態,’H’表示正面朝上,’T’表示背面朝上。

輸出

第1行:1個字串,若Alice能夠獲勝輸出"Alice",否則輸出"Bob"

樣例輸入
8
HHTHTTHT
樣例輸出
Bob

解題思路:

這題是白書上翻棋子游戲的簡化版,將二維改成了一維,其實道理是一樣的。

我們可以把每個正面朝上的第i個硬幣都看成一個有i個石子的石子堆,那麼就要以下3種後續操作:

1.只把當前硬幣翻過來,那麼就相當於把整堆石子取完。

2.把當前硬幣i翻過來,並且把之前一枚反面朝上的硬幣j也翻過來,當前硬幣i就無法再操作,而原本無法操作的硬幣j就變成可以操作的了,那麼就相當於i個石子的石子堆被j個石子的石子堆替代了,其實也就是把i個石子的石子堆刪到只剩j個石子。

3.把當前硬幣i翻過來,並且把之前一枚正面朝上的硬幣j也翻過來,這時候硬幣i和硬幣j都無法再操作,講道理就是把兩堆石子都取了,但是我們可以轉換一下,兩個相同的數異或一下也等於0,所以把i個石子的石子堆變成j個石子效果也是一樣的,所以也就是把i個石子的石子堆刪到只剩j個石子。

那麼第i個硬幣就和大小為i的石子堆的sg值是一樣的,也就是i本身,我們只需要把所有正面朝上的硬幣的位置異或一下就得出答案了。

而白書上的翻棋子游戲就是擴充套件到二維:

題意:一個棋盤上每個格子有一個棋子,每次操作可以隨便選一個朝上的棋子(x,y),代表第i行第j列的棋子,選擇一個形

(x,b)或(a,y)(其中b < y,a < x)的棋子,然後把它和(x,y)一起翻轉,無法操作的人輸。

座標為(x,y)的棋子就可以等價為兩堆大小分別為x、y的石子,證明(口胡)跟上面的翻硬幣是一樣的。

#include <bits/stdc++.h>  
using namespace std;  
  
int main()  
{  
    int n;  
    cin>>n;  
    int sg=0, i, j;  
    char x;  
    scanf("\n");  
    for(i=1; i<=n; i++)  
    {  
        scanf("%c", &x);  
        if(x=='H')sg^=i;  
    }  
    if(sg==0)printf("Bob\n");  
    else printf("Alice\n");  
}