【Light OJ】No More Tic-tac-toe (博弈 SG函数)

来源:互联网 发布:c语言经典程序100例 编辑:程序博客网 时间:2024/05/01 03:10

题目链接:

http://acm.bnu.edu.cn/v3/problem_show.php?pid=13319


一道典型的求解SG函数的题目,校内组队赛中遇到此题。开题时有比较清晰的解题思路,但是因为不常刷题导致写代码效率低下,一道题的代码写了近3h。最终因为一个没发现的小错误导致没能AC。实力还是太弱,还是需要努力。

先说说我错误的原因。大家知道求SG函数时,我们只需要把那些直接与终止态相连的状态作为递归终点,手算出它们的SG值即可(一般很容易算),剩下的状态的SG函数直接递归求解即可。以此题为例,我用一个结构体p{l,r,len}来表示一个长度为len,左侧方块为l,右侧方块为r的状态,l,r有三种状态0,1,2,分别代表没放标记、放‘X’和放'O'。这样,我们只需要手算出长度为1的状态{0,0,1}、{0,1,1}、{0,2,1}...的答案,其他状态直接搜索求解即可,但我画蛇添足地手算了len=2时各个状态的SG函数。然后....就算错了....(让我一个人静一静...

所以说不要做一些画蛇添足的事,求SG函数还是让它它自己去算吧。

接下来说一下算过SG函数之后得到的规律:l==r&&r==0时,SG=(len&1)?1:0;l==0||r==0时,SG=len;剩下的情况中,若l==r,则SG=1否则SG=0。


代码:


#define sc scanf#define pr printf#include<cstdio>#include<cstring>#include<algorithm>#include<map>#define LL long longusing namespace std;const int N = 200;const LL mod = 1000000007;struct p {    int l,r,len;    bool operator < (const p& b)const {        if(len==b.len&&l==b.l)            return r<b.r;        else if(len==b.len)            return l<b.l;        else return len<b.len;    }};char s[N];p c[N];map<p,int> mapp;int dfs(p a) {    if(mapp.count(a))        return mapp[a];    if(a.len == 0)        return 0;    else if(a.len==1) {        if(a.l==0||a.r==0)            return 1;        else if(a.l==a.r)            return 1;        else            return 0;    } else {        int ans = 0;        bool vis[200];        memset(vis,0,sizeof(vis));        p p1,p2;        p1.l = a.l;        p1.r = 1;        p2.l = 1;        p2.r = a.r;        for(int i=0; i<a.len; ++i) {            if(a.l==1&&i==0)                continue;            if(a.r==1&&i==a.len-1)                continue;            p1.len = i;            p2.len = a.len-i-1;            vis[dfs(p1)^dfs(p2)] = 1;        }        p1.r = 2;        p2.l = 2;        for(int i=0; i<a.len; ++i) {            if(a.l==2&&i==0)                continue;            if(a.r==2&&i==a.len-1)                continue;            p1.len = i;            p2.len = a.len-i-1;            vis[dfs(p1)^dfs(p2)] = 1;        }        for(int i=0;; ++i)            if(!vis[i]) {                ans = i;                break;            }        mapp[a] = ans;        return mapp[a];    }}int main() {    //freopen("input.in","r",stdin);    int T;    int cas = 0;    sc("%d",&T);    while(T--) {        sc("%s",s);        int l = strlen(s);        int ct=0;        int tmp = 0;        c[0].l = 0;        int num = 0;        for(int i=0; i<l; ++i) {            if(s[i]=='X') {                c[tmp].r = 1;                c[tmp].len = ct;                c[++tmp].l = 1;                ct = 0;                num++;            } else if(s[i]=='O') {                c[tmp].r = 2;                c[tmp].len = ct;                c[++tmp].l = 2;                ct = 0;                num++;            }            if(s[i]!='.')                continue;            ct++;        }        c[tmp].r = 0;        c[tmp].len = ct;        c[++tmp].l = 0;        ct = 0;        int res =0;        for(int i=0; i<tmp; ++i)            res ^=dfs(c[i]);//打表找规律        pr("Case %d: ",++cas);        if(((num&1)&&res)||((!(num&1))&&(!res)))            puts("No");        else            puts("Yes");    }    return 0;}


0 0
原创粉丝点击