【转】今天看了关于博弈论的一些东西,大概明白了一些,但是也说不出个所以然来。主要就是要分析必胜和必败的局面,对于我来说理解起来比较费劲。这里就只能知道这么一回事,还需要在以后的做题中慢慢理解。现在就以两道简单题来做一下,领悟一下。
第一道是poj1067,结题报告是从别人那里转载来的:
题目描述:
Description
Input
Output
Sample Input
2 1
8 4
4 7
Sample Output
0
1
0
解题报告:
有两堆石子,给定两堆石子的数量,可以进行如下两种操作:1、从某一堆中拿走一定数量的石子2、从两堆石子中拿走相同数量的石子两个人轮流拿,假设都按照最优策略来操作,谁输呢? 问题类型:威佐夫博弈 分析:当某一个人面对(0,0)的局势时,必败,我们把面临该局势必败的局势称为必败局势。易知上一个必败局势为(1,2),因为不管面临该局势的人采用何种操作,下一个人都可以使之面临(0,0)的趋势,则接下去的必败局势分别为(3,5),(4,7),(5,9)...... 设第k+1个必败局势为(ak,bk),ak<=bk,有如下性质: ak=(sqrt(5)+1)*k/2;bk=ak+k; 我们称不满足该条件的局势称为必胜局势,因为总可以进行一次操作使得下一个人面临必败局势。 下面我们要做的工作就是判断该局势(a,b)是不是必败局势。我们首先要估算k;假设k是必败局势,k=(sqrt(5)-1)*a/2;对k取整,如果a=(sqrt(5)+1)*k/2不成立,我们可以对k进行修正:k++;此时,若b=a+k则该局势为必败局势。
代码实现:
第二题是暑假第二次比赛的一道题:<span style="font-size:18px;">#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<math.h> using namespace std; int main() { int a, b, k; double r = (sqrt(5.0)+1)/2.0; while(~scanf("%d%d", &a, &b)){ if(a>b) swap(a,b); k = b - a; if(a != int(r*k)) printf("1\n"); else printf("0\n"); } return 0; } </span>
题目描述:
Box Game There are two identical boxes. One of them contains n balls, while the other box contains one ball. Alice and Bob invented a game with the boxes and balls, which is played as follows:
Alice and Bob moves alternatively, Alice moves first. For each move, the player finds out the box having fewer number of balls inside, and empties that box (the balls inside will be removed forever), and redistribute the balls in the other box. After the redistribution, each box should contain at least one ball. If a player cannot perform a valid move, he loses. A typical game is shown below:
When both boxes contain only one ball, Bob cannot do anything more, so Alice wins.
Question: if Alice and Bob are both clever enough, who will win? Suppose both of them are very smart and always follows a perfect strategy.
Input
There will be at most 300 test cases. Each test case contains an integer n ( 2n109) in a single line. The input terminates by n = 0.Output
For each test case, print a single line, the name of the winner.Sample Input
2 3 4 0
Sample Output
Alice Bob Alice解题思路:通过观察我们可以发现,Bob想要赢,也就是打印出Bob的名字时,输入的数字是3、7、15、31......也就是2^n-1.所以我们只需要在这些数字打印出Bob就行。我写了一份代码,也在网上看到一份代码,思路的是一样的,但是可以从中学到一点技巧,也就是n&(n-1)的用法。先贴我的代码,在贴一份别人的代码。
实现代码:
#include<cstdio> int main() { int n; while(~scanf("%d", &n)){ if(n==0) break; int sum = 1; int flag = 0; for(int i = 0; i<100; i++){ sum *= 2; if(n == sum-1) { flag = 1; break; } } if(flag) printf("Bob\n"); else printf("Alice\n"); } return 0; }
别人的代码:#include <iostream> #include <cstring> #include <algorithm> #include <cstdio> #include<math.h> #include<cstdlib> using namespace std; #include<stdio.h> int main() { int n; while(~scanf("%d",&n)) { if(n==0) break; ++ n; if((n & (n - 1))) printf("Alice\n"); else printf("Bob\n"); } return 0; }
顺带学习n&(n-1)的一种用法:
n&(n-1)作用:将n的二进制表示中的最低位为1的改为0,先看一个简单的例子: n = 10100(二进制),则(n-1) = 10011 ==》n&(n-1) = 10000 可以看到原本最低位为1的那位变为0。 可以判断一个数是否是2的方幂 n > 0 && ((n & (n - 1)) == 0 )