关闭

庞果网-单词博弈

1384人阅读 评论(4) 收藏 举报
分类:
 
题目详情

甲乙两个人用一个英语单词玩游戏。两个人轮流进行,每个人每次从中删掉任意一个字母,如果剩余的字母序列是严格单调递增的(按字典序a < b < c <....<z),则这个人胜利。两个人都足够聪明,甲先开始,问他能赢么?

输入: 一连串英文小写字母,长度不超过15,保证最开始的状态不是一个严格单增的序列。

输出:1表示甲可以赢,0表示甲不能赢。

例如: 输入 bad, 则甲可以删掉b或者a,剩余的是ad或者bd,他就赢了,输出1。

又如: 输入 aaa, 则甲只能删掉1个a,乙删掉一个a,剩余1个a,乙获胜,输出0。

 

此题属于明显的博弈问题,但是比较遗憾的是在我的acm生涯中没接触过博弈论这个部分,因此刚开始尝试利用模拟的方法解决,利用极大极小搜索+alpha beta剪枝找到最优解,实现后提交结果超时了,继续优化后没有发现比较好的剪枝方法,因此不得不换个思路。

 

百度了下博弈论的基本概念,顿时茅塞顿开,解决这个问题,只需要知道两个基本概念即可!

1.一个局势只能是必胜局势或必败局势两种
2.如果一个局势能通过操作变为必败局势,那么这个局势就是必胜的,否则是必败的

 

此题即求初始的序列是否是必胜局势,不难发现此题的必败局势是升序序列,因为在到达这个局势时对手已经赢了,我们可以枚举当前局势的每种子局势,判断它是否是必胜还是必败,然后得到当前局势的状态。

 

static const int fastbit[32] = {
    0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
    31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
};

#define FASTBIT(X) (fastbit[((unsigned int)(((X)&-(X))*0x077CB531U))>>27])

int state[(1<<16)-1]; //0代表必败,1代表必胜

int who(char *word)
{
    int len;
    int i ,j ,t ,k;
    len = strlen(word);
    
    memset(state, 0, sizeof(state));
    
    for(i = 1 ;i < (1<<len) ;i ++) {
        
        t = i;
        k = -1;
        while(t) {
            
            j = FASTBIT(t);
            if(k >= 0 && word[k] >= word[j]) { //判断是否升序
                break;
            }
            k = j;
            t &= ~(t&-t);
        }
        
        if(!t) {
            continue;
        }
        
        t = i;
        k = 0;
        while(t && !state[i]) { //枚举当前局势的子局势
            
            j = FASTBIT(t);
            state[i] = state[(t&~(1<<j))|k]^1;
            k = ((1<<(j+1))-1)&i;
            t &= ~(t&-t);
        }
        
    }
    
    return state[(1<<len)-1];
}


 

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:235942次
    • 积分:3579
    • 等级:
    • 排名:第9138名
    • 原创:108篇
    • 转载:43篇
    • 译文:1篇
    • 评论:87条
    最新评论