1. 程式人生 > >P1288 取數遊戲II

P1288 取數遊戲II

存在 define 奇數 png turn ret 硬幣 一道 fin

題目描述

有一個取數的遊戲。初始時,給出一個環,環上的每條邊上都有一個非負整數。這些整數中至少有一個0。然後,將一枚硬幣放在環上的一個節點上。兩個玩家就是以這個放硬幣的節點為起點開始這個遊戲,兩人輪流取數,取數的規則如下:

(1)選擇硬幣左邊或者右邊的一條邊,並且邊上的數非0;

(2)將這條邊上的數減至任意一個非負整數(至少要有所減小);

(3)將硬幣移至邊的另一端。

如果輪到一個玩家走,這時硬幣左右兩邊的邊上的數值都是0,那麽這個玩家就輸了。

如下圖,描述的是Alice和Bob兩人的對弈過程,其中黑色節點表示硬幣所在節點。結果圖(d)中,輪到Bob走時,硬幣兩邊的邊上都是0,所以Alcie獲勝。

技術分享

(a)Alice (b)Bob (c)Alice (d)Bob

現在,你的任務就是根據給出的環、邊上的數值以及起點(硬幣所在位置),判斷先走方是否有必勝的策略。

輸入輸出格式

輸入格式:

第一行一個整數N(N≤20),表示環上的節點數。

第二行N個數,數值不超過30,依次表示N條邊上的數值。硬幣的起始位置在第一條邊與最後一條邊之間的節點上。

輸出格式:

僅一行。若存在必勝策略,則輸出“YES”,否則輸出“NO”。

輸入輸出樣例

輸入樣例#1:
【輸入1】
4
2 5 3 0
【輸入2】
3
0 0 0
輸出樣例#1:
【輸出1】
YES
【輸出2】
NO

一臉蒙蔽的看完題解。、

這是一道數學題。。。

我們來舉個例子:有一條邊R從x指向y,它的數值大於0,AB對弈,現在A走

那麽如果數值為1,A走過去,數值變為0,B就走不回來了

如果數值為2,A走過去,數值變為1,如果B走回來,A不就死了?我們認為他們都足夠聰明,怎麽會做這種事情呢?(假設過來的前一條邊已經走完了,數值為0)

如果數值大於3(我們假定為3),A走過去,數值變為2,B如果仁慈地走回來,數值變為1,這樣不就浪費了一步?

B如果按照題意殘忍地用最佳行動走回來,取光所有數值,那麽數值變為0,這條路就封死了,A做了一件無意義的事情,還封死了自己可以走的一條路,這對於先手的A而言是不利的,

這兩種方法都明顯有違雙方最優的前提。

[/color][b]所以我們可以知道,無論是A走還是B走,即無論是先手走還是後手走,每走過一條路都一定取完,這樣問題就簡單了[/b]

因為至少有個0,所以就簡單了一點。。誰把對手逼到死路(兩邊都是0的)就贏了

從起始點開始向兩邊找,只要有一邊到0邊距離為奇數就是先手贏反之後手贏

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<algorithm>
 6 #define lli long long int
 7 const int MAXN=2333; 
 8 int n,s[MAXN];
 9 int judge(int p)
10 {
11     return p&1;
12 }
13 void read(int &n)
14 {
15     char c=+;int x=0;bool flag=0;
16     while(c<0||c>9)
17     {c=getchar();if(c==-)flag=1;}
18     while(c>=0&&c<=9)
19     {x=x*10+(c-48);c=getchar();}
20     flag==1?n=-x:n=x;
21 }
22 int main()
23 {
24     read(n);
25     for (int i=1;i<=n;i++) 
26     read(s[i]);
27     int a=0;
28     while(s[++a]);
29     int b=0;
30     while(s[n+1-(++b)]);
31     if (judge(--a)||judge(--b))  
32     printf("YES");  
33     else printf("NO");
34 }

P1288 取數遊戲II