博弈思想学习指南
博弈思想学习指南
典题合集
前置芝士
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]
[结论]
[证明]
。。。。。。
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;
}