博弈思想学习指南

博弈思想学习指南

典题合集

前置芝士

Nim 游戏

[problem description]

甲,乙两个人玩 nim 取石子游戏。

nim 游戏的规则是这样的:地上有 \(n\) 堆石子(每堆石子数量小于 \(10^4\)),每人每次可从任意一堆石子里取出任意多枚石子扔掉,可以取完,不能不取。每次只能从一堆里取。最后没石子可取的人就输了。假如甲是先手,且告诉你这 \(n\) 堆石子的数量,他想知道是否存在先手必胜的策略。

[input]

本题有多组测试数据。

第一行一个整数 \(T\)\(T\le10\)),表示有 \(T\) 组数据

接下来每两行是一组数据,第一行一个整数 \(n\),表示有 \(n\) 堆石子,\(n\le10^4\)

第二行有 \(n\) 个数,表示每一堆石子的数量.

[output]

\(T\) 行,每行表示如果对于这组数据存在先手必胜策略则输出 Yes,否则输出 No

[a.in]

2
2
1 1
2
1 0

[a.out]

No
Yes

[solved]

[结论]

img

[证明]

。。。。。。

void solve() {
    //freopen("a.in","r",stdin);
    //freopen("a.out","w",stdout); 
    int n;
    int s=0;
    cin>>n;
    for(int i=1,x;i<=n;i++){
    	cin>>x;
    	s^=x;
    }
    if(s) cout<<"Yes"<<endl;
    else cout<<"No"<<endl;
}

Nim游戏扩展

[problem description]

在Nim游戏的基础上,如果先取必胜,请输出第一次该如何取,如果是先取必败,则输出lose。

[output]

第一行输出两个整数 a,b,表示第一次从第 b 堆取出 a 个。第二行为第一次取火柴后的状态。如果有多种答案,则输出⟨b,a⟩ 字典序最小的答案( 即 b 最小的前提下,使a 最小)

[solved]

const int N=500010;

int k,a[N];
void solve() {
    //freopen("a.in","r",stdin);
    //freopen("a.out","w",stdout); 
    cin>>k;
    int s=0;
   	for(int i=1;i<=k;i++){
   		cin>>a[i];
   		s^=a[i];
   	}
   	if(!s)  {cout<<"lose"<<endl;return;}
   	for(int i=1;i<=k;i++){
   		if((a[i]^s)>=a[i]) continue;
   		cout<<a[i]-(a[i]^s)<<" "<<i<<endl;
   		a[i]^=s;
   		break;
   	}
   	for(int i=1;i<=k;i++) cout<<a[i]<<" ";
   	cout<<endl;
}
posted @ 2023-11-29 23:36  White_Sheep  阅读(4)  评论(0编辑  收藏  举报