文思海辉第一届在线编程大赛--开源探究

题目详情

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

输入: 一连串英文小写字母,长度不超过15,保证最开始的状态不是一个严格单增的序列。
输出:1表示甲可以赢,0表示甲不能赢。
例如: 输入 bad, 则甲可以删掉b或者a,剩余的是ad或者bd,他就赢了,输出1。

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


题目分析:其实一看题就知道是一个博弈的算法题。

最基本的最大最小搜索,alpha-beta剪枝

高级一点的状态空间缓存,最小窗口移动等。


先贴一个写最大最小搜索的代码吧。

#include<iostream>
#include<string>
using namespace std;
#define         MAX_NUM         15

struct State//该结构表示状态,也可看做搜索树中的一个节点
{
    char QP[MAX_NUM];
    bool IsDel[MAX_NUM];
    bool win[MAX_NUM];
}; //用来保存搜索树中状态节点的数组

class Test {
public:
    static int who (string word)
    {
    Init(word);
    int s = AutoDone(StateInit, 0);
    return s;
    };

private:
    static void Init(const string &a)   //初始化函数
    {
        for(int i = 0; i < MAX_NUM; i++)
        {
            StateInit.IsDel[i] = true;
        }

        for(int i = 0; i < a.size() && i < MAX_NUM; i++) {
            StateInit.QP[i] = a[i];
            StateInit.IsDel[i] = false;
        }
    };

    static void PrintQP(const struct State &s, int l, bool rt, bool iswin)  //打印状态
    {
        return;
        cout<< l << "\t" << "now is:";
        for(int i=0; i<MAX_NUM; i++)
        {
            if (!s.IsDel[i])
                cout<< s.QP[i] <<" ";
        }
        if (rt)
        {
            if (iswin)
                cout<<" Win" << endl;
            else
                cout<<" Lose" << endl;
        }
    };

    static bool IsWin(State s) //判断是否赢了
    {
        char last = '0';
        for (int i = 0; i < MAX_NUM; i++) {
            if (last == '0') {
                if (!s.IsDel[i]) {
                    last = s.QP[i];
                }
            } else {
                if (!s.IsDel[i]) {
                    if (s.QP[i] <= last)
                        return false;
                    else
                        last = s.QP[i];
                }
            }
        }
        return true;
    };

    //计算机通过该函数决定走哪一步
    static bool AutoDone(const struct State &state, int l)
    {
        bool max_min = (l % 2);
        if(IsWin(state))//如果赢了
        {
            return max_min;
        }

        State status[MAX_NUM];
        for (int i = 0; i < MAX_NUM; i++)
        {
            memcpy(&status[i], &state, sizeof(State));
            if(status[i].IsDel[i]) continue;
            //假设删除一个
            status[i].IsDel[i] = true;
            status[i].win[i] = AutoDone(status[i], l+1);
            if (!max_min) {
                if (status[i].win[i]) return true;
            } else {
                if (!status[i].win[i]) return false;
            }
            //status[i].IsDel[i] = false;
        }


        if (!max_min) {
            for (int i = 0; i < MAX_NUM; i++)
            {
                if(status[i].IsDel[i]) continue;
                if (status[i].win[i]) {
                    return true;
                }
            }

            return false;
        } else {
            for (int i = 0; i < MAX_NUM; i++)
            {
                if(status[i].IsDel[i]) continue;
                if (!status[i].win[i]) {
                    return false;
                }
            }
            return true;
        }
    };

    static struct State StateInit;
};

State Test::StateInit;

//主程序
int main()
{
    cout<<Test::who("bad")<<endl;
    return 0;
}

后记:

这个题限制了最长字符不超过15,如果知道最大最小搜索就知道字符长度对计算时间的影响非常大。

这个代码计算结果应该没问题,但是字符长时间开销没有优化。提交的时候应为超时失败了。

如果纯用标准算法,要想15步在3秒内算完还是比较困难的,所以针对题目做特例化优化是一个方向。

欢迎大家在基础上优化提高。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值