標籤:
【題目】
Description The funny stone game is coming. There are n piles of stones, numbered with 0, 1, 2, ..., n − 1. Two persons pick stones in turn. In every turn, each person selects three piles of stones numbered i, j, k (i < j, j ≤ k and at least one stone left in pile i). Then, the person gets one stone out of pile i, and put one stone into pile j and pile k respectively. (Note: if j = k, it will be the same as putting two stones into pile j). One will fail if he can’t pick stones according to the rule. David is the player who first picks stones and he hopes to win the game. Can you write a program to help him? The number of piles, n, does not exceed 23. The number of stones in each pile does not exceed 1000. Suppose the opponent player is very smart and he will follow the optimized strategy to pick stones. Input Input contains several cases. Each case has two lines. The first line contains a positive integer n (1 ≤ n ≤ 23) indicating the number of piles of stones. The second line contains n non-negative integers separated by blanks, S0, . . . , Sn−1 (0 ≤ Si ≤ 1000), indicating the number of stones in pile 0 to pile n − 1 respectively. The last case is followed by a line containing a zero. Output For each case, output a line in the format ‘Game t: i j k’. t is the case number. i, j and k indicates which three piles David shall select at the first step if he wants to win. If there are multiple groups of i, j and k, output the group with the minimized lexicographic order. If there are no strategies to win the game, i, j and k are equal to ‘-1’.
Sample Input 4 1 0 1 100 3 1 0 5 2 2 1 0 Sample Output Game 1: 0 2 3 Game 2: 0 1 1 Game 3: -1 -1 -1
|
【題目翻譯】
David 玩一個石子遊戲。遊戲中,有n堆石子,被編號為0..n-1。兩名玩家輪流取石子。每一輪遊戲,每名玩家選取3堆石子i,j,k(i<j,j<=k,且至少有一枚石子在第i堆石子中),從i中取出一枚石子,並向j,k中各放入一枚石子(如果j=k則向k中放入2顆石子)。最先不能取石子的人輸。
請編程協助David。
石子堆的個數不會超過23,每一堆石子不超過1000個。
【分析】
首先,假設第i堆有xi個石子,那麼可以先把xi%2。
因為在同一堆中的兩顆石子是一模一樣的。對方對這顆石子做什麼,你就可以對另外一顆石子做同樣的事,相當於這兩顆一樣的石子不存在。
因為每顆石子可以變成兩顆放到後面去,也就是說它的轉移狀態和它的編號有關。
可以將每一顆石子看作是一堆石子,如果它是第p堆中的石子,把麼它所代表的這堆石子的個數為n-1-p。
因為石子堆是互不干擾的,因此這個遊戲可以看作由若干個只有一堆石子的遊戲組成。(把其單獨考慮開來)
求它能到達的子狀態的尼姆和更新自己的sg值即可。跟掃樓梯一題差不多,即使這堆石子的個數為偶數個,他可能還是有用的,即可以拆分也把狀態改變為平衡狀態的,要把這個也考慮上。(好像說得不是很清楚,具體看代碼吧~~)
代碼如下:(看錯資料範圍了,懶得改了,就醬吧~)
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 #include<queue> 7 using namespace std; 8 #define Maxn 1010 9 10 int n;11 int a[2*Maxn],b[2*Maxn],sg[2*Maxn];12 bool vis[2*Maxn];13 14 void get_sg(int x)15 {16 memset(vis,0,sizeof(vis));17 for(int i=1;i<x;i++)18 for(int j=i;j<x;j++)19 {20 vis[sg[i]^sg[j]]=1;21 }22 for(int i=0;i<=2000;i++) 23 if(vis[i]==0) {sg[x]=i;break;}24 }25 26 bool output(int x,int now)27 {28 for(int i=x-1;i>=1;i--)29 for(int j=i;j>=1;j--)30 if((sg[i]^sg[j])==now)31 {32 printf("%d %d %d\n",n-x,n-i,n-j);33 return 1;34 }35 return 0;36 }37 38 int main()39 {40 int kase=0;41 for(int i=1;i<=1000;i++) get_sg(i);42 while(1)43 {44 scanf("%d",&n);45 if(n==0) break;46 int ans=0;47 for(int i=1;i<=n;i++) scanf("%d",&a[i]);48 for(int i=1;i<=n;i++) b[i]=a[n-i+1];49 for(int i=1;i<=n;i++)50 {51 if(b[i]%2==1) ans^=sg[i];52 }53 printf("Game %d: ",++kase);54 if(ans==0) {printf("-1 -1 -1\n");continue;}55 int mx=0;56 for(int i=0;(1<<i)<=ans;i++)57 if((1<<i)&ans) mx=(1<<i);58 for(int i=n;i>=1;i--) 59 if(b[i]!=0) {if(output(i,ans^sg[i])) break;}60 }61 return 0;62 }[UVA1378]
2016-04-17 17:12:38
【UVA1378】A Funny Stone Game (博弈-求SG值-輸出方案)