题意:给出n个石子和m,俩人取,每次最多取m个,不能取的输,问输的是谁。
思路:典型巴什博弈,可以发现,如果一共有m+1个物品,我们去取它,先手至少要取一个,却又把所有的物品取不完,这样就导致了后手的必赢。
如果物品数小于等于能取的数目,是必胜的,因为只用取一次,如果是大于能取的数目的,我们可以把总数n分解为(m+1)∗x+r
所以,先手只要先取走r个石子,然后根据后手取的石子数b,使接下来先手取的石子数a满足a+b=m+1就可以了,这样就能保证如果是可以分解为(m+1)∗x+r的话,先手必胜,如果只能分解为(m+1)∗x的话,先手必败
#include<bits/stdc++.h>
using namespace std;
int n, m, t;
int main() {
cin >> t;
while(t--) {
cin >> n >> m;
int r = n % (m + 1);
if(r)cout << "first" << endl;
else cout << "second" << endl;
}
return 0;
}
题意:1堆石子有n个,两人轮流取.先取者第1次可以取任意多个,但不能全部取完.以后每次取的石子数不能超过上次取子数的2倍。取完者胜.先取者负输出"Second win".先取者胜输出"First win".
思路:斐波那契博弈,结论是n如果是斐波那契数列的数就是先手输,不然后手输。证明不会。
#include<bits/stdc++.h>
using namespace std;
#define ll long long;
const int maxn = 1e6 + 19;
int n, m[500], t;
int main() {
m[1] = 1, m[2] = 1;
for(int i = 3; i <= 46; i++)
m[i] = m[i - 1] + m[i - 2];
while(cin >> n && n) {
int f = 0;
for(int i = 1; i <= 46; i++)
if(n == m[i]) {
f = 1;
}
if(f)cout << "Second win" << endl;
else cout << "First win" << endl;
}
return 0;
}
题意:有三个数字n,p,q,表示一堆硬币一共有n枚,从这个硬币堆里取硬币,一次最少取p枚,最多q枚,如果剩下少于p枚就要一次取完。两人轮流取,直到堆里的硬币取完,最后一次取硬币的算输。对于每一行的三个数字,给出先取的人是否有必胜策略,如果有回答WIN,否则回答LOST。
思路:巴什博弈的变形,当n%(p+q)==0时,我们第一次取q个,然后每次根据它取的i个,我们取p+q-i个,然后最好剩下p个它必须取完,当n%(p+q)==s时,当s<=p时,我们输,大于p则我们赢。
#include<bits/stdc++.h>
using namespace std;
#define ll long long;
const int maxn = 1e6 + 19;
int main() {
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int n, p, q;
while(cin >> n >> p >> q) {
if(n % (p + q) == 0) cout << "WIN" << endl;
else { int a = n % (p + q);
if(a <= p) cout << "LOST" << endl;
else cout << "WIN" << endl;
}
}
return 0;
}
4、P2252 取石子游戏
题意:有两堆石子,数量任意,可以不同。游戏开始由两个人轮流取石子。游戏规定,每次有两种不同的取法,一是可以在任意的一堆中取走任意多的石子;二是可以在两堆中同时取走相同数量的石子。最后把石子全部取完者为胜者。
思路:
威佐夫博弈(Wythoff Game):
有两堆各若干的物品,两人轮流从其中一堆取至少一件物品,至多不限,或从两堆中同时取相同件物品,规定最后取完者胜利。
直接说结论了,若两堆物品的初始值为(x,y),且x<y,则另z=y-x;
记w=(int)[((sqrt(5)+1)/2)*z ];
若w=x,则先手必败,否则先手必胜。
#include<bits/stdc++.h>
using namespace std;
#define ll long long;
const int maxn = 1e6 + 19;
int main() {
int t, n, m;
cin >> n >> m;
if(m < n)
swap(m, n);
if(m == n)
return 0 * puts("1");
int z = m - n;
int w = (int)(((sqrt(5) + 1) / 2) * z );
if(w == n)
cout << 0;
else
cout << 1;
return 0;
}