您的位置:首页 > 其它

大白书 2.4节 组合游戏(博弈论)

2015-12-04 14:20 369 查看
大白书 2.4节 组合游戏

博弈论笔记:

1)必胜必败状态:

a)一个状态为必胜状态,充要条件是后续状态有一个必败状态

b)一个状态为必败状态,充要条件是后续状态全是必胜状态

2)SG函数

a)定义:SG[i] = {所有i的后继SG值中,不在这些值之中的最小非负整数}

b)一个状态为必败状态,当且仅当这个状态的SG值为0

c)通常可以用暴力的方法求出参见第二道题,数据过大时参见第一道题

3)Nim和与SG函数的应用

a)Nim和:一个父游戏的状态等于子游戏状态的异或和。

b)一个游戏的SG值,等于所有子游戏的SG值的异或和

UVA 1146

看的题解

找规律,n为偶数SG值为n/2,奇数为SG[i] = SG[i/2]

源码:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#include <iostream>
#include <string>
using namespace std;
#define LL long long
LL sg(LL u)
{
if(u % 2 == 0)  return u / 2;
return sg(u / 2);
}
int main()
{
int T;
scanf("%d", &T);
while(T--){
int n;
scanf("%d", &n);
LL state = 0;
while(n--){
LL u;
scanf("%lld", &u);
state ^= sg(u);
}
if(state == 0)   printf("NO\n");
else    printf("YES\n");
}
return 0;
}


UVA 10561

看的题解和别人代码

对于一个X,存在控制区间即[x-2,x+2],在这个区间内放X就输了。

然后根据这个性质得出SG函数以及的特判输赢的情况。

然后枚举每个不在控制区间、不为X的位置变成1后SG是否为0,得出所有位置的解。

源码:

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
#include <iterator>
using namespace std;
const int MAXN = 200 + 5;
int vis[MAXN];
int sg[MAXN];
void init()
{
sg[0] = 0;
sg[1] = sg[2] = sg[3] = 1;
for(int i = 4 ; i < MAXN ; i++){
memset(vis, 0, sizeof(vis));
for(int j = 1 ; j <= i ; j++){  ///枚举以那个点为划分点,然后[i-2,i+2]均失效
int l = max(0, j - 3);
int r = max(0, i - j - 2);
//            if(i == 5){
//                printf("l = %d, r = %d\n", l, r);
//            }
vis[sg[l] ^ sg[r]] = 1;
}
for(int j = 0 ; ; j++){
if(vis[j] == 0){
sg[i] = j;
break;
}
}
}
}
char op[MAXN];
int ts[MAXN], s[MAXN];
int n;
vector<int>ans;
bool check1()
{
int ok = 0;
ans.clear();
for(int i = 1 ; i <= n ; i++){
if(i > 2 && ts[i - 2] == 1 && ts[i - 1] == 1) ok = 1, ans.push_back(i);
if(i <= n - 2 && ts[i + 1] == 1 && ts[i + 2] == 1)   ok = 1, ans.push_back(i);
if(i < n && i > 1 && ts[i] == 0 && ts[i - 1] == 1 && ts[i + 1] == 1)   ok = 1, ans.push_back(i);
}
return ok;
}
int SG()
{
int state = 0;
int cnt = 0;
//    printf("/***");
//    for(int i = 1 ; i <= n ; i++)   printf("%d ", s[i]);
//    printf("***///\n");
for(int i = 1 ; i <= n ; i++){
if(s[i] == 1){
//            printf("cnt = %d\n", cnt);
state ^= sg[cnt];
cnt = 0;
}
else    cnt++;
}
//    printf("cnt = %d\n", cnt);
state ^= sg[cnt];
//    printf("state = %d\n", state);
return state;
}
int main()
{
//    freopen("UVA 10561.in", "r", stdin);
init();
//    printf("sg[5] = %d\n", sg[5]);
int T;
scanf("%d", &T);
while(T--){
scanf("%s", op);
n = strlen(op);
for(int i = 0 ; i < n ; i++){
if(op[i] == 'X')    ts[i + 1] = 1;
else    ts[i + 1] = 0;
}
for(int i = 1 ; i <= n ; i++){
s[i] = 0;
for(int j = max(1, i - 2) ; j <= min(n, i + 2) ; j++){
if(ts[j] == 1){
s[i] = 1;
break;
}
}
}
if(check1()){///第一步即胜利
printf("WINNING\n");
vector<int>::iterator newend = unique(ans.begin(), ans.end());
ans.erase(newend, ans.end());
int f = 1;
for(vector<int>::iterator it = ans.begin() ; it != ans.end() ; it++){
if(f)   f = 0;
else    printf(" ");
printf("%d", *it);
}
printf("\n");
continue;
}
else if(SG() == 0){
printf("LOSING\n\n");
}
else{
//            printf("///***");
//            for(int i = 1 ; i <= n ; i++)   printf("%d ", s[i]);
//            printf("***///\n");
ans.clear();
for(int i = 1 ; i <= n ; i++){
if(s[i] == 0){
memcpy(ts, s, sizeof(ts));  ///ts用于保存s的初始状态
for(int j = max(i - 2, 1) ; j <= min(i + 2, n) ; j++)
s[j] = 1;
//                    printf("i = %d, SG() = %d\n", i, SG());
if(SG() == 0)   ans.push_back(i);
memcpy(s, ts, sizeof(ts));
}
}
printf("WINNING\n");
int f = 1;
for(vector<int>::iterator it = ans.begin() ; it != ans.end() ; it++){
if(f)   f = 0;
else    printf(" ");
printf("%d", *it);
}
printf("\n");
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: