以下是大神对博弈问题的总结, 让我受益匪浅:
博弈最重要的三点:(以后做题经常利用这三点性质):
注意:P点是必败局势,就是说无论是谁面对P点都必败
N点是必胜局势,也就是说面对此局势的人有必胜策略
终结点,是结局,无法再继续博弈
(1)所有终结点是必败点(P点); //容易理解
(2)从任何必胜点(N点)操作,至少有一种方法可以进入必败点(P点); //就是那种我们要走的方法
(3)无论如何操作,从必败点(P点)都只能进入必胜点(N点)//仔细思考,发现确实是这样
综上博弈中,一个状态不是必胜,就是必败
很多时候,找不到规律时,可以利用以上的性质搜索解决问题。
巴什博弈(容易理解,没什么好说的)
只有一堆n个物品,两人轮流从这堆物品中取物,规定每次至少取一个,最多取m个。最后取光者获胜。
先手胜利的条件: n = (m+1)c+s时;取走s个;
也就是说:一个人面对当前石子个数是m+1的倍数时,这个人就输了;
典型例题:http://acm.hdu.edu.cn/showproblem.php?pid=1846
代码:
#include<stdio.h>
int main(){
int T, n, m;
scanf("%d", &T);
while(T--){
scanf("%d %d", &n, &m);
if(n % (m + 1) == 0)
printf("second\n");
else
printf("first\n");
}
return 0;
}
类似的题目还有两个人轮流报数,谁先报到100,谁就赢了。。。
威佐夫博弈(结论好理解,证明太难了我不会):
有两堆石子,数量任意,可以不同。
游戏开始由两个人轮流取石子。游戏规定,每次有两种不同的取法,
一是可以在任意的一堆中取走任意多的石子;
二是可以在两堆中同时取走相同数量的石子。
最后把石子全部取完者为胜者。
(0,0)是终结点
(1,2)是之前一个必败点
(3,5),(4,7),(6,10),(8,13)...都是必败点
找规律发现每个自然数都只出现一次,并且是前面没有出现过的最小自然数。
这里有一个结论:跟黄金分割有关
我们把第k个必败点的两个数表示成(ak,bk);
那么
b(k) = a(k) + k; //看规律得出的
a(k) = k * (1 + sqrt(5))/2 //关于这个公式的出处http://scimath.unl.edu/MIM/files/MATExamFiles/Cotton_MATpaper_Final_EDITED.pd或者在http://yjq24.blogbus.com/logs/42826226.html
题目:http://acm.hdu.edu.cn/showproblem.php?pid=1527
代码:
#include<stdio.h>
#include<math.h>
int main(){
int a, b, k, temp;
int max, min;
while(scanf("%d %d", &a, &b) != EOF){
if(a == b && a != 0){
printf("1\n");
continue;
}
// if(a == b && a == 0){
// printf("0\n");
// continue;
// }
max = a > b ? a : b;
min = a < b ? a : b;
k = max - min;
temp = (k * (sqrt(5.0) + 1)) / 2;
if(temp == min && temp + k == max){
printf("0\n");
}
else
printf("1\n");
}
return 0;
}
斐波那契博弈:
有一堆石子,两个人轮流从其中取走一定的石子,取走最后所有石子的人为赢家,不过得遵循如下规则:
1.第一次取不能取完,至少取1颗.
2.从第二次开始,每个人取的石子数至少为1,至多为对手刚取的石子数的两倍。
结论:如果一个人当前面对的石子数是斐波那契数,那么这个人就一定输了.(证明在这里:http://blog.csdn.net/dgq8211/article/details/7602807,证明过程很复杂,但是记住结论很轻松)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2516
代码:#include<stdio.h>
#include<string.h>
int main(){
int n;
int a, b, c;
while(scanf("%d", &n), n){
a = 1, b = 1;
c = 2;
while(c < n){
c = a + b;
a = b;
b = c;
}
if(c == n){
printf("Second win\n");
}
else
printf("First win\n");
}
return 0;
}