有两堆石子,两个人轮流去取.每次取的时候,只能从较多的那堆石子里取,并且取的数目必须是较少的那堆石子数目的整数倍.最后谁能够把一堆石子取空谁就算赢.
比如初始的时候两堆石子的数目是25和7
25 7 –> 11 7 –> 4 7 –> 4 3 –> 1 3 –> 1 0
选手1取
选手2取
选手1取
选手2取
选手1取
最后选手1(先取的)获胜,在取的过程中选手2都只有唯一的一种取法。
给定初始时石子的数目,如果两个人都采取最优策略,请问先手能否获胜。
这又是一道博弈论的题,似乎是一道很基础的题,但是我依然不会做。
是这个样子的,设a≤ba≤b,则若a≤2ba≤2b或b|a,则先手必胜,否则先手只有一种取法,就取下这种,看后手是否会赢,如此递归下去,时间复杂度是log级的。
考虑为什么这种情况下先手必胜。
对于b|a的情况是显然的,而若a≤2ba≤2b,我们考虑a%b,假如a%b≤⌊b2⌋a%b≤⌊b2⌋,则显然我们取b∗⌊ab−1⌋b∗⌊ab−1⌋即可令后手选法唯一且在其选过之后,留给先手的是a≤ba≤b或b|a的局面;而同样的道理,若a%b>⌊b2⌋a%b>⌊b2⌋,我们只需取b∗⌊ab⌋b∗⌊ab⌋即可。
所以我们便找到了必胜态。
代码很短:
#include<cstdio>
#include<algorithm>
#include<iostream>
using namespace std;
int main(){
int n,m,tot;
for(scanf("%d%d",&n,&m);n||m;scanf("%d%d",&n,&m)){
if(n<m)swap(n,m);
if(n/m>=2||n%m==0)puts("win");
else{
tot=0;
do{
n-=m;
swap(n,m);
++tot;
}while(n/m<2&&n%m);
if(tot&1)puts("lose");
else puts("win");
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
= =但是我感觉,博弈论的题证明起来好说,正面推的话就蛋疼;做题的时候。。还是先打表找规律,再深入思考吧。。不过大体思路似乎都是寻找必败态或必胜态,然后再从一个搞出另一个。