当前位置:网站首页>威佐夫博弈
威佐夫博弈
2022-08-11 11:34:00 【Here_SDUT】
描述
有两堆各若干个物品,两个人轮流从任意一堆中取出至少一个或者同时从两堆中取出同样多的物品,规定每次至少取一个,至多不限,最后取光者胜利。
分析
我们用(a,b)来表示某个时刻两堆石子的数量,我们先从简单情况进行分析,当石子数为(0,0)时,则游戏结束,上一局的人获胜。
如果现在局面是(1,2),先手有四种取法:
- 第一堆里取1个,得到(0,2),后手可以一次取完,后手获胜。
- 第二堆里取1个,得到(1,1),后手两堆里分别取一个,后手获胜。
- 第二堆里取2个,得到(1,0),后手获胜。
- 第一堆取1个,第二堆去1个,得到(0,1),后手获胜。
从上面的分析可以看到,无论先手怎么拿。后手都有办法获胜,我们将其称为先手必输态,(1,2)就是一个先手必输态。
按照上述的分析方法往下分析我们可以发现:
(0,0,)
(1,2)
(3,5)
(4,7)
(6,10)
(8,13)
(9,15)
(11,18)
等等都是先手必输态。
寻找上面这些必输态的规律,可以发现:每个必输态的两堆石子数的差值是递增且相差1,并且每个状态的第一个数字都是前面所有状态里未出现的最小自然数。并且,每个状态的第一个值等于当前状态的差值乘上黄金分割率(0.618),关于为什么会是黄金分割率,可以看知乎的一篇文章:传送门
例题
时间限制:1000ms 内存限制:65536KiB
三个蒟蒻一台戏
Description
今天,3个蒟蒻很开心,因为要去参加一年一度的 XCPC 诗词大赛,由于经费有限只能选择乘坐火车前往比赛地点。由于路途遥远,无聊的三人决定玩个游戏来消磨时间。由于对骑士精神的追崇,3人决定采取决斗的方式进行游戏(即1v1),另外一个人作为裁判。由于没有事先准备,手上只有一些纸团,三人想出了一个简单的游戏,规则如下:由裁判选取两堆数量任意的纸团,参与游戏的两个人轮流取走纸团,每次有两种取法:
- 在任意的一堆中取走任意多的纸团。
- 在两堆中同时取走任意多的相同数量的纸团。
最后取完纸团的获胜,由于三人都是游戏高手,所以每次都会采取最优的策略,给出两堆纸团的数量,让你判断先手会胜还是会败,如果会胜,给出先手的第一次取纸团的所有方案。注意每回合至少取一个纸团。
Input
多组输入,每行两个非负整数 n 和 m (0 \le n,m\le100000) ,表示两堆纸团的初始个数,n = m = 0 时退出。测试组数不超过100000。
Output
如果先手会败则输出0,否则输出1,并输出第一次取完纸团后两堆剩下的纸团数,先输出小的一堆数量,在输出多的一堆的数量,中间用一个空格分开。如果有多种策略,按照较小一堆的纸团的数量升序排序后输出。
Sample
Input
1 2
5 8
4 7
2 2
646 583
0 0Output
0
1
3 5
4 7
0
1
0 0
1 2
1
101 164
360 583
399 646分析
就是模板题,先判断是否为先手必输态,否则就必胜,对于输出策略,就是输出所有可能的必输态,我们假设第一堆纸团数小于第二堆纸团数,一共三种可能:
- 两堆纸团各取相同多的纸团,这种情况两堆纸团的差值是不变的,所有根据差值判断一下是否有合法的必输态即可。
- 第一堆纸团不变,第二堆纸团取若干个,那么只要第二堆纸团数大于第一堆纸团对应的必输态的另外一堆纸团数即可,这里需要注意的是题目要求先输出小的一堆,再输出多的一堆,所以要先判断一下第二堆取完后和第一堆的大小关系。
- 第二堆纸团不变,第一堆纸团取若干个,那么只要第一堆纸团数大于第二堆纸团对应的必输态的另外一堆纸团数即可。
注意点:由于有1e5组样例,每组最大1e5,所以不能暴力找策略,可以用预处理,比如某个必输态为(a,b),那么可以映射出mp[a] = b,mp[b] = a。注意输出局面时可能会输出重复局面,记得去重,推荐使用set,既可以去重又可以排序。
代码
#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int maxn = 1e5 + 10;
const int inf = 0x3f3f3f3f;
const double PI = acos(-1.0);
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
int mp[maxn];
double C = (1 + sqrt(5.0)) / 2;//黄金分割的更精确表示
void init() {
for (int i = 0; i < maxn; i++) {
int x = i * C, y = x + i;
mp[x] = y;
if (y > maxn) break;
mp[y] = x;
}
}
int main() {
int m, n;
init();
while (cin >> n >> m && n + m) {
set<PII> ans;
if (n > m) swap(n, m);
if ((int)((m - n) * C) == n)
puts("0");
else {
puts("1");
int x = C * (m - n), y = x + (m - n);
if (n - x == m - y && m - y > 0) ans.insert({x, y});
if (mp[m] < n) ans.insert({mp[m], m});
if (mp[n] < m) {
if (mp[n] < n)
ans.insert({mp[n], n});
else
ans.insert({n, mp[n]});
}
for (auto it : ans) {
printf("%d %d\n", it.first, it.second);
}
}
}
return 0;
}边栏推荐
- 文献阅读(185)Co-design
- 性能测试的环境以及测试数据构造
- 七、一起学习Lua 函数
- BAT "exclusive" Internet giant Android senior engineer interview questions: 174 questions allow you to do the interview
- Tool_RE_IDA基础字符串修改
- PerfView专题 (第一篇):如何寻找热点函数
- 鸿海董事长刘扬伟:市场对智能手机和其他消费电子产品的需求正在放缓
- 如何用100元制作一块全志V853的AI 开发板
- EastWave应用:负折射现象实时演示
- PerfView project (first) : how to find hot spots function
猜你喜欢

Volatile关键字的作用

通过热透镜聚焦不同类型的高斯模式

StratoVirt 中的虚拟网卡是如何实现的?

TX12 + ExpressLRS 915MHz RC控制链路配置及问题汇总

重要消息丨.NET Core 3.1 将于今年12月13日结束支持

a-upload上传图片

EastWave应用:负折射现象实时演示

Through the thermal lens focus on different types of gaussian model
![C# Call AutoNavi Map API to obtain latitude, longitude and positioning [Detailed 4D explanation with complete code]](/img/39/75a32a787c4e85026a768fd5781f25.png)
C# Call AutoNavi Map API to obtain latitude, longitude and positioning [Detailed 4D explanation with complete code]

如何批量下载hugging face模型和数据集文件
随机推荐
2022 OceanBase 年度发布会:发布四大策略,迈入4.0时代
1元限时秒杀 | 接口抓包分析与Mock实战训练营
exist和in的区别
flutter面试题收集
Azure IoT & NVIDIA Jetson 开发基础
学习二叉树
MySQL --- storage engine
五分钟教你内网穿透
如何在游戏中实现一场下雨效果
go语言学习:并发编程(定时器/select/并发安全锁)
vending machine
【毕业设计】老人心率脉搏血压体征监测手表 - stm32 单片机 嵌入式 物联网
Small target stunt | Complete the small target detection upgrade of Yolov5 in the easiest way!
从滴滴被罚款事件思考企业数据治理问题
蚂蚁集团开源密码学基础库 BabaSSL 正式更名“铜锁”
C-V2X八大误区澄清和发展辩思
C# Call AutoNavi Map API to obtain latitude, longitude and positioning [Detailed 4D explanation with complete code]
爆赞!阿里P8首次分享出基于Docker的企业级Redis实战开源笔记
Web3 创业者指南:如何为你的产品构建一个去中心化社区?
d共享左值