SG函数学习

尼姆博弈就是sg函数的简单体现

学习粗:https://blog.csdn.net/luomingjun12315/article/details/45555495

//f[N]:可改变当前状态的方式,N为方式的种类,f[N]要在getSG之前先预处理
//SG[]:0~n的SG函数值
//S[]:为x后继状态的集合
int f[N],SG[MAXN],S[MAXN];
void  getSG(int n){
    int i,j;
    memset(SG,0,sizeof(SG));
    //因为SG[0]始终等于0,所以i从1开始
    for(i = 1; i <= n; i++){
        //每一次都要将上一状态 的 后继集合 重置
        memset(S,0,sizeof(S));
        for(j = 0; f[j] <= i && j <= N; j++)
            S[SG[i-f[j]]] = 1;  //将后继状态的SG函数值进行标记
        for(j = 0;; j++) if(!S[j]){   //查询当前后继状态SG值中最小的非零值
            SG[i] = j;
            break;
        }
    }

}

 题:http://acm.hdu.edu.cn/showproblem.php?pid=1536

 分析,对石子堆打表出sg函数

 异或和要求只能去的数

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=10005;
int s[110],sg[N+4],f[110];
void getsg(int n){
    sg[0]=0;
    for(int i=1;i<N;i++){
        memset(s,0,sizeof(s));
        for(int j=1;f[j]<=i&&j<=n;j++){
            s[sg[i-f[j]]]=1;
        }
        for(int j=0;j<N;j++){
            if(!s[j]){
                sg[i]=j;
                break;
            }
        }
    }
}
int main(){
    int k;
    while(scanf("%d",&k)!=EOF){
        if(k==0)
            break;
        for(int i=1;i<=k;i++)
            scanf("%d",&f[i]);
        sort(f+1,f+1+k);
        getsg(k);
        int t;
        scanf("%d",&t);
        while(t--){
            int n;
            scanf("%d",&n);
            int ans=0;
            for(int x,i=1;i<=n;i++){
                scanf("%d",&x);
                ans^=sg[x];
            }
            if(ans)
                printf("W");
            else
                printf("L");
        
        }    

        printf("\n");
    }
    return 0;
}
View Code

 题:http://acm.hdu.edu.cn/showproblem.php?pid=5724

由状压得来的sg函数。

题意:n*20的棋盘,给你n行,每行m个,每位选手把棋子移到右边第一个空的位置,移不动则输,问先手是否必赢

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pb push_back
const int M=1e3+3;
int sg[1<<21];
int sta[30];
void init(){
    
    for(int i=0;i<(1<<20);i++){
        memset(sta,0,sizeof(sta));
        for(int j=19;j>=0;j--)
            if(i&(1<<j)){
                for(int k=j-1;k>=0;k--){
                    if(!(i&(1<<k))){
                        sta[sg[i^(1<<k)^(1<<j)]]=1;
                        break;
                    }
                }
            }
            
        for(int j=0;j<=19;j++)
            if(sta[j]==0){
                sg[i]=j;
                break;
            }
    }
}
int main(){
    init();
    int t;
    scanf("%d",&t);
    while(t--){
        int n;
        int ans=0;
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            int m;
            int sign=0;
            scanf("%d",&m);
            while(m--){
                int x;
                scanf("%d",&x);
                sign|=1<<(20-x);
            }
            ans^=sg[sign];
            
        }
        if(ans)
            puts("YES");
        else
            puts("NO");
    }
    return 0;
}
View Code

 

posted @ 2019-11-01 17:45  starve_to_death  阅读(162)  评论(0编辑  收藏  举报