您的位置:首页 > 其它

LA 4411 Addition-Subtraction Game(无环图上的博弈,SG)

2014-01-14 21:25 232 查看
LA  4411 Addition-Subtraction Game

题目内容过多,此处不再描述。

典型的SG定理的应用,把“整个图只有一个顶点的value=1,其余节点的value=0,的游戏”看成单个子游戏。

好好利用亦或运算的性质可大大降低复杂度,如:偶数个相同子游戏的SG值的亦或 必为零 。

参考代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn = 105;
int value[maxn] ,to[maxn][20] , num[maxn] ,K[maxn] ,E , V , R;
int sg[maxn], cnt[1<<15];  // cnt[x] 为x的二进制中1的个数。

int mex(vector<int> &s){
sort(s.begin() , s.end());
if(s[0] > 0) return 0;
int s_size = s.size();
for(int i=1;i<s_size ;i++) {
if(s[i]-s[i-1] > 1) return s[i-1] + 1;
}
return s[s_size - 1] + 1;
}
int SG(int u){
if(sg[u] != -1) return sg[u];
if(num[u] == 0) return sg[u] = 0;
int max_b = 1<<num[u];
vector<int>S;
for(int b=0 ; b<max_b ;b++){   // 状态压缩,枚举哪些后继点增加奇数次。
if(cnt[b] > K[u]) continue; // 最多只能选择K[u]个
if((cnt[b]^K[u])&1) continue; // 注意奇偶对应!
int g = 0;               //后继状态的SG值
for(int i=0;i<num[u] ;i++) if(b&(1<<i)) {
g ^= SG(to[u][i]);
}
S.push_back(g);
}
return sg[u] = mex(S);
}
int main()
{
for(int x=0;x<(1<<15);x++){
int c = 0 , t = x;
while(t) c+= t&1 , t>>=1;
cnt[x] = c;
}

int T;
scanf("%d" ,&T);
for(int game=1;game<=T;game++){
memset(num , 0, sizeof(num));
memset(sg, -1 ,sizeof(sg));
scanf("%d%d",&V,&E);
int x,y;
for(int i=0;i<E;i++){
scanf("%d%d",&x,&y);
to[x][num[x]++] = y;
}
for(int i=0;i<V;i++)
scanf("%d",&K[i]);

printf("Game#%d:\n" ,game);
scanf("%d" ,&R);
for(int round = 1 ;round <= R ;round++){
for(int i=0;i<V;i++) scanf("%d" ,&value[i]);
int sum_sg = 0;
for(int i=0;i<V;i++) if(value[i]&1){   //偶数个必为0,不用考虑
sum_sg ^= SG(i);               // 亦或奇数次,等价于亦或1次
}
printf("Round#%d: ",round);
if(sum_sg) printf("WINNING\n");
else printf("LOSING\n");
}
printf("\n");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  博弈 SG定理