单词博弈解题思路 文思海辉编程大赛

来源:互联网 发布:工业数据采集系统 编辑:程序博客网 时间:2024/05/22 05:01

博客,这里开始了我人生的又一个有意义的第一次——第一次写个人博客。

。。。好吧,主要还是学习如何写博客,记录自己成长的过程,在这里就记下这题“单词博弈”解题思路,写写个人思路,也非常欢迎江湖有志同道合的朋友共同探讨!

/******************************************************************华丽的分割线********************************************************************************/

题目详情
甲乙两个人用一个英语单词玩游戏。两个人轮流进行,每个人每次从中删掉任意一个字母,如果剩余的字母序列是严格单调递增的(按字典序a < b < c <....<z),则这个人胜利。两个人都足够聪明(即如果有赢的方案,都不会选输的方案 ),甲先开始,问他能赢么?
输入: 一连串英文小写字母,长度不超过15,保证最开始的状态不是一个严格单增的序列。
输出:1表示甲可以赢,0表示甲不能赢。
例如: 输入 bad, 则甲可以删掉b或者a,剩余的是ad或者bd,他就赢了,输出1。
又如: 输入 aaa, 则甲只能删掉1个a,乙删掉一个a,剩余1个a,乙获胜,输出0。

题目不难理解,就是一场博弈,看谁先得到必胜态,思路就是去分析当前状态得到SG函数,如果下一次操作得到的状态全部是必败状态,那么推出当前状态即为必胜状态;否则,如果下次操作得到的状态中有必胜状态,那么当前状态则定义为必败状态,因为操作者可以通过当前状态到达必胜状态。
由此,我们可以通过DFS搜索,从当前状态出发,预测能得到的状态有哪些,并尝试记录已经求出的状态,避免重复搜索,实现记忆化搜索。这里,我们注意到字母序列的长度最大为15,因此我们一共会得到2^15种状态,这样做的效果很不错,希望你会喜欢!得意
#include <stdio.h>#include <iostream>#include <string>using namespace std;int map[33010];int wlen;bool checkUp(int stat,string word){    char ch=123;    for (int i=0;i<wlen;++i)    {        if ((1<<i)&stat)        {            if (word.at(wlen-i-1)>=ch)            {                return false;            }            else            {                ch=word.at(wlen-i-1);            }        }    }    return true;}int DFS(int stat,string word){    if (map[stat]>-1)    {        return map[stat];    }    if (checkUp(stat,word))    {        return map[stat]=0;    }    int res=1;    for (int i=0;(1<<i)<=stat;++i)    {        if ((1<<i)&stat)        {            res&=DFS((1<<i)^stat,word);        }    }    return map[stat]=res^1;}class Test {public:   static int who (string   word)    {    wlen=word.length();    int stat=(1<<wlen)-1;    for (int i=0;i<=stat;++i)    {        map[i]=-1;    }    return DFS(stat,word);        return 0;    }};//start 提示:自动阅卷起始唯一标识,请勿删除或增加。int main(){       cout<<Test::who("Test")<<endl;   } //end //提示:自动阅卷结束唯一标识,请勿删除或增加。