###題目連接###php
題目大意:ios
有一個 0 ~ n+1 的數軸,Alice 站在 0 點處,Bob 站在 n+1 點處。在 1 ~ n 上各有着權值。 Alice 每次向右移動 1 格或兩格 ,Bob 每次向左移動 1 格或 2 格(他們必定要移動),Alice 移動到 n+1 處中止,Bob 移動到 0 處中止,直到他們都中止的時候,此時若 Alice 所通過的數值總和大於 Bob 的數值總和,則 Alice 勝出,反則 Bob 勝出。Alice 先出手,兩人足夠聰明,走到的數值必須拿走,而走到過的數值不能再被拿走。spa
分析:code
一、顯然是博弈題。blog
二、dfs 枚舉全部可能,當 Alice 出手時,有兩種走法(走一步或兩步)。好比 Alice 走一步後,枚舉 Bob 走到的地方(也只有兩種走法),而後判斷是否 Bob 不管怎樣走, 此時 Alice 必贏,則 「此刻 Alice 走一步」 爲必勝態,由於若 Alice 走這一步以後, Bob 不管怎麼操做都沒法獲勝,則此時爲必勝態。get
三、故枚舉 Alice 的兩次走法,假如此時 Alice 處於位置 x ,若此刻走到 u 可使得自身處於必勝態,則返回 true ,告訴 dfs 的上一層中,走到 x 處能夠轉化爲必勝態。string
博弈點分析:假如此刻位置爲 x ,如今兩種走法可使得 x 走到 u1 或者 u2。若 u1 與 u2 同時爲必勝點,則 x 處也爲必勝點;若 u1 是必勝點,u2 是必敗點,則 x 處也爲必勝點,由於 選手足夠聰明,走到 x 處後會走到 u1 處,故 x 爲必勝點;若 u1 與 u2 同爲必敗點,則 x 也爲必敗點。這就是爲何 必勝點能夠轉化爲必敗點或必勝點,而必敗點只能轉化爲必敗點。it
細節處理:io
一、此題不該該 vis 設爲 bool 類型,由於走過的點會重複,很差判斷。class
二、最好走到臨界點的時候特判(x==n+1 以及 y==0)。
代碼以下:
#include<iostream> #include<algorithm> #include<string.h> using namespace std; int t,n; int a[18]; int tox[2]={1,2}; int toy[2]={-1,-2}; int vis[18]; bool dfs(int x,int y,int res,int ans){ if(x==n+1&&y==0) return res>ans; bool q; for(int i=0;i<2;i++){ q=true; int u,res1; if(x==n+1) u=x,res1=0; else{ u=x+tox[i]; if(u>n+1) continue; vis[u]++; res1=(vis[u]==2?0:a[u]); } for(int j=0;j<2;j++){ int v,ans1; if(y==0) v=y,ans1=0; else{ v=y+toy[j]; if(v<0) continue; vis[v]++; ans1=(vis[v]==2?0:a[v]); } bool w=dfs(u,v,res+res1,ans+ans1); if(y!=0) vis[v]--; if(!w) { q=false; break; } } if(x!=n+1) vis[u]--; if(q) return true; } return false; } int main() { scanf("%d",&t); while(t--){ scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); a[0]=a[n+1]=0; if(dfs(0,n+1,0,0)) printf("Alice\n"); else printf("Bob\n"); } }