博弈思想学习指南

博弈思想学习指南

典题合集

前置芝士

Nim 游戏

[problem description]

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

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

[input]

本题有多组测试数据。

第一行一个整数 TT10),表示有 T 组数据

接下来每两行是一组数据,第一行一个整数 n,表示有 n 堆石子,n104

第二行有 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;
}

本文作者:White_Sheep

本文链接:https://www.cnblogs.com/taotao123456/p/17866217.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   White_Sheep  阅读(7)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
🔑