HDU2176 【 Nim博弈】 SG函数求解
取(m堆)石子游戲
m堆石子,兩人輪流取.只能在1堆中取.取完者勝.先取者負輸出No.先取者勝輸出Yes,然后輸出怎樣取子.例如5堆 5,7,8,9,10先取者勝,先取者第1次取時可以從有8個的那一堆取走7個剩下1個,也可以從有9個的中那一堆取走9個剩下0個,也可以從有10個的中那一堆取走7個剩下3個.
Input
輸入有多組.每組第1行是m,m<=200000. 后面m個非零正整數.m=0退出.?
Output
先取者負輸出No.先取者勝輸出Yes,然后輸出先取者第1次取子的所有方法.如果從有a個石子的堆中取若干個后剩下b個后會勝就輸出a b.參看Sample Output.?
Sample Input
2 45 45 3 3 6 9 5 5 7 8 9 10 0Sample Output
No Yes 9 5 Yes 8 1 9 0 10 3Nim游戲:
有N堆石子,每堆石子的個數是有限的,合法的操作是:選擇一堆石子,拿走若干顆,不能不拿;最后拿走最后一顆石子者勝。
結論:
必敗狀態:a1^a2^......^an=0(奇異局勢)
必勝狀態:a1^a2^.......^an=k (其中k不為零)
遇到奇異局勢的選手必敗
證明:
N=1時,先手第一次可以全部取完,先手必勝;
1.對于某個局面(a1,a2,...,an),若a1^a2^...^an!=0,一定存在某個合法的移動,將ai改變成ai'后滿足a1^a2^...^ai'^...^an=0。
不妨設a1^a2^...^an=k,則一定存在某個ai,它的二進制表示在k的最高位上是1(否則k的最高位那個1是怎么得到的)。
這時ai^k<ai一定成立。則我們可以將ai改變成ai'=ai^k,此時?a1^a2^...^ai'^...^an=a1^a2^...^an^k=0。
2.對于某個局面(a1,a2,...,an),若a1^a2^a3...^an=0,先手遇到奇異局勢,先手必敗;
一定不存在某個合法的移動,將ai改變成ai'后,足?a1^a2^...^ai'^...^an=0。
因為異或運算滿足消去率,由a1^a2^...^an=a1^a2^...^ai'^...^an可以得到ai=ai'。所以將ai改變成ai'不是一個合法的移動
答案:
- 如果a1^a2^a3^......^an=0,先手遇到奇異局勢,先手必敗;
- 如果a1^a2^a3^......^an=k,先手必勝,先手選擇一堆石子,取temp個之后,出現奇異局勢,后手必敗
假設從第 i 堆石子中取走(ai^k)個石子,(a1^a2^a3^...ai^....^an)^k=k^k=0,剩余石子必然是奇異局勢,后手必敗;
在這道題中如果當前是必勝的話,那么就要下一個移動的人必敗,所以就要改變一個ai變成ai'使得原本的a1^...ai^...^an!=0變成a1^...ai'...^an=0,可以利用ai^k<ai' 判斷
import java.util.*; import java.math.*;public class Main{static int MAXN=(int)(2e5+10);static int[] a=new int[MAXN];//存儲每堆石子的個數static int n;public static void main(String[] args) {Scanner cin=new Scanner(System.in);while(cin.hasNext()) {n=cin.nextInt();if(n==0) break;int ret=0;for(int i=1;i<=n;i++) {a[i]=cin.nextInt();ret^=a[i];//根據Nim游戲的策略,對每堆石子進行異或運算} if(ret==0) {//先手遇到奇異局勢,必敗System.out.println("No");continue;}System.out.println("Yes");//先手取一次之后,讓后手面對奇異局勢for(int i=1;i<=n;i++) {int temp=a[i]^ret;if(temp<=a[i]) System.out.println(a[i]+" "+temp);}}cin.close();} }取硬幣游戲?
時間限制:?1 Sec??內存限制:?128 MB
題目描述
現在有n堆硬幣,第i堆硬幣有xi個硬幣。yoyo和灰灰輪流進行操作,每次操作只能選擇一堆硬幣,然后從這一堆硬幣中取任意多個硬幣(1~x,x為該堆最大數量),但不能不取。輪到的人如果沒有硬幣可取,則輸。yoyo先手,誰能獲勝?
輸入
首行輸入t,代表t組樣例
每組樣例第一行輸入n,代表n堆硬幣。n<=1000;
接下來n個數字(a1,a2,a3......an)代表每堆硬幣的硬幣數。an<=1000;
輸出
輸出誰贏。yoyo必勝輸出yoyo,否則輸出zhazhahui
樣例輸入
2 3 2 3 4 4 2 3 4 5樣例輸出
yoyo zhazhahui分析:
對于一堆硬幣,假設有x個,則這堆硬幣取一次后,剩余的個數可能是mex={0,1,2.....x-2,x-1},
SG表示最小的不屬于mex集合的最小非負整數,即SG(x)=x;
所以ans=x1^x2^x3.......xn;若ans=0,說明先手必敗,否則先手必勝
#include<bits/stdc++.h> using namespace std;int main() {ios::sync_with_stdio(false);int n,t;cin>>t;while(t--){cin>>n;int x,ans=0;for(int i=0;i<n;i++){cin>>x;ans^=x;}if(ans==0)printf("zhazhahui\n");elseprintf("yoyo\n");}return 0;}?
總結
以上是生活随笔為你收集整理的HDU2176 【 Nim博弈】 SG函数求解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 动态规划下的巴什博弈
- 下一篇: HDU1247 字典树 Hat’s Wo