博弈论1
组合游戏
特征
- 两个玩家
- 一个状态集合
- 游戏规则是指明玩家从一个状态可以移动到哪些状态
- 玩家轮流进行移动
- 如果当前处于的状态无法移动,则说明游戏结束
- (大部分时候)无论玩家如何选择,游戏会在有限步操作内结束
通常的解题步骤
- 首先设置两种状态P,N 态
- P:走到这个状态的玩家(previous player)赢的状态
- N:从这个状态走的玩家(next player)赢的状态
- 确定终态是 P 还是 N
- 从终态逆推打表找规律
- 验证规律的正确性
- 确定初态是 p 还是 N
- 初态是 P 意味着先手输
- 否则意味着先手赢
P N 态的性质
- 至少能走到一个P态的状态是N态
- 下一步只能走到N态的状态是P态
题目分析
bash游戏
只有一堆n个物品,两个人轮流从这堆物品中取物,规定每次至少取一个,最多取m个.最后取光者得胜
枚举m,进行倒推打表
比如:
m = 1
0(P) <—— 1(N) <—— 2(P) <—— 3(N) .....
m = 2
0(P) <—— 1(N) <—— 2(N) <—— 3(P) .....
m = 3
0(P) <—— 1(N) <—— 2(N) <—— 3(N) <—— 4(P).....
然后我们可以初步的确定结论为
if(num % (m + 1) == 0) num 为 P 态
else num 为 N 态
最后可以去确定n的状态,判断先手是赢还是输
题目和代码
#include<iostream>
#include<algorithm>
using namespace std;
int t;
void solve()
{
int n,k;
cin >> n >> k;
if(n % (k + 1)) puts("A");
else puts("B");
}
int main()
{
cin >> t;
while(t --) solve();
return 0;
}
eleting Divisors
- 首先我们可以确定终态为质数,我们可以直接确定质数为P态
- 从1开始从小到大确定每个数的状态
- 根据PN性质,能到达P态的是N态,只能到达N态的是P态,然后打表找规律
- 发现奇数全为P态
- 偶数分为两种情况
- 如果是2的整奇数次幂,那么为P态
- 否则为N态
打表代码
#include<iostream>
#include<cstring>
#include<algorithm>
#include<fstream>
#include<vector>
#include<unordered_map>
using namespace std;
unordered_map<int,bool> mp;
vector<int> device;
void get(int x)
{
for(int i = 2; i * i <= x; i ++)
if(x % i == 0)
{
device.push_back(i);
device.push_back(x / i);
}
}
int main()
{
for(int i = 0; i <= 200; i++)
{
device.clear();
get(i);
if(device.empty()) mp[i] = 1;
else
{
bool flag = true;
for(int d : device)
if(mp[i - d])
{
flag = false;
break;
}
mp[i] = flag;
}
}
fstream fstrm("output.txt");
for(int i = 1; i <= 200; i++) fstrm << i << ' ' << (mp[i]? 'P':'N') << endl;
fstrm.close();
return 0;
}
提交代码
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
int t;
void solve()
{
int n;
cin >> n;
if(n % 2) puts("Bob");
else
{
int cnt = 0,pos = -1;
for(int i = 0; i < 32; i++)
if(n >> i & 1)
{
cnt ++;
if(cnt == 1) pos = i;
}
//cout << cnt << ' ' << pos << endl;
if(cnt == 1 && pos & 1) puts("Bob");
else puts("Alice");
}
}
int main()
{
cin >> t;
while(t--) solve();
return 0