單詞博弈解題思路 文思海輝編程大賽

博客,這裏開始了我人生的又一個有意義的第一次——第一次寫個人博客。

。。。好吧,主要還是學習如何寫博客,記錄自己成長的過程,在這裏就記下這題“單詞博弈”解題思路,寫寫個人思路,也非常歡迎江湖有志同道合的朋友共同探討!

/******************************************************************華麗的分割線********************************************************************************/

題目詳情
甲乙兩個人用一個英語單詞玩遊戲。兩個人輪流進行,每個人每次從中刪掉任意一個字母,如果剩餘的字母序列是嚴格單調遞增的(按字典序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 //提示:自動閱卷結束唯一標識,請勿刪除或增加。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章