1. 程式人生 > >洛谷P3150 pb的遊戲(1)

洛谷P3150 pb的遊戲(1)

由於 轉移 做的 sam class bits 再次 我們 兩個人

題目背景

(原創)

有一天 pb和zs玩遊戲 你需要幫zs求出每局的勝敗情況

題目描述

遊戲規則是這樣的: 每次一個人可以對給出的數進行分割,將其割成兩個非零自然數,之後由另一個人選擇留下兩個數中的其中一個;之後由另一個人進行分割這個剩下的數,重復步驟……

當一個人無法對數進行分割的時候遊戲結束,另一個人獲勝

現在要你求出N次遊戲的勝敗

每局由pb先進行分割,如果pb贏輸出"pb wins" 如果zs贏輸出"zs wins"

註:雙方都是絕頂聰明的

輸入輸出格式

輸入格式:

第一行一個數N,表示數據組數

之後N行,每行一個數M,表示每局初始的數

輸出格式:

共N行,每行一串字符 表示遊戲結果

輸入輸出樣例

輸入樣例#1:
5
1
3
7
20
5
輸出樣例#1:
zs wins
zs wins
zs wins
pb wins
zs wins

說明

1<N<50 1<=m<=1000000000

題目詳解

這道題是洛谷博弈論專題的第一道入門題, 然而剛開始我是不會做的, 畢竟是道入門題, 我博弈論還沒入門呢.

這道題的做法就是: 如果m為偶數, 那麽先手贏(即pb), 如果m為奇數, 那麽後手贏(即zs).

<strong> 做法很簡單, 可是我們要知道怎麽做的</strong>

說實話我對於他們兩個都聰明絕頂, 都會按照最優策略來走很不感冒. 既然他們聰明絕頂, 那麽先手明知道m為奇數時自己會輸, 為什麽不灑脫一點走呢? 也許亂走出奇跡?

那我們來試試看. 當m = 13時, 先手為什麽會輸. 前提是先手知道自己按照最優策略會輸(因為輪到他分時為奇數), 所以開始亂走.

先手:13 = 4 +9
後手:選4, 4 = 1 +3
先手:不得已選3, 3=1+2
後手:選2,2=1+1
後手贏

不服? 再來一把

先手:13=6+7
後手:選6,6=1+5
先手:選5,5=1+4
後手:選4,4=1+3
先手:3=1+2
後手:2=1+1
後手贏

經過了兩把測試, 我們不管先手怎麽走(亂走或所謂最優策略),只要他手裏是奇數,都不得不拆成奇數+偶數, 那麽後手只要選擇偶數, 他就可以把這個數化成m = n + 1(後手的最優策略), 把奇數轉移給先手. 這樣經過若幹次轉移之後, 後手手裏一定會是2,然後2 = 1 + 1, 後手就贏了.

所以, 其實手裏是奇數的人是沒有勝算的, 所以這個狀態是必敗態. 而手裏是偶數的人是有必勝的可能的, 只有他才有最優策略而且只要他按照最優策略走, 他一定會贏, 因此這個狀態是必勝態. 當然, 如果他sa, 就可能將必勝態拱手讓人.

而理解這個博弈論問題的關鍵, 就是擁有偶數的策略: 每次減一. 因而可以再次將偶數態(必勝態)轉移過來.

事實上, 剛接觸此題時, 我對所謂絕頂聰明, 所謂最優策略很困惑, 兩個人博弈, 憑什麽說我走的是最佳策略結果卻輸了? 我是不是應該把所有走法都試一遍, 然後都輸給你才算我輸?

我的理解是: 必敗態從來沒有最佳策略, 博弈也不是雙方的博弈, 而是處在必勝態的那方和自己博弈. 而這場博弈, 由於絕頂聰明的前提, 是必勝的, 而我們要做的, 只是找出誰有跟自己博弈的機會.

感性理解一下:這個題無非就是判斷奇偶數

AC代碼如下

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int main()
 4 {
 5     int n,a;
 6     cin>>n;
 7     for(int i=1;i<=n;++i)
 8     {
 9         cin>>a;
10         if(a%2==1)
11         cout<<"zs wins"<<endl;
12         else 
13         cout<<"pb wins"<<endl;
14     } 
15 return 0;
16 }

洛谷P3150 pb的遊戲(1)