英雄会“单词博弈”最快的解?(别信,反正我没得奖)

前一段英雄会的有奖题目,貌似有三千多人参加,通过率三十分之一。

当时看到题目的时候正好空闲,被奖品诱惑了,花了半个小时思考,半个小时编码,测试用例一次通过。

后来,结果出来了,没有后来了。所以我自夸最快的解,只能算是吸引眼球。

后来我看到几个网上的解题思路,都没有这个简单,不少人都用了复杂的数据结构;

还看到有人说他的程序运行时间在毫秒级,我心想,呃,太慢了吧……

哥也贴代码出来吧,至少不枉费我花的一个多小时啊。


题目详情
甲乙两个人用一个英语单词玩游戏。两个人轮流进行,每个人每次从中删掉任意一个字母,

如果剩余的字母序列是严格单调递增的(按字典序a < b < c <....<z),则这个人胜利。

两个人都足够聪明(即如果有赢的方案,都不会选输的方案 ),甲先开始,问他能赢么?


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


函数头部:
C:int who (char * word);
C++:int who (string word);
Java:public static int who(String in);
C# :public static  int who(string word);

思路:长度不超过15的字符串,甲乙轮流取走,用位标记取走的情况,

一个unsigned short就可以表示搜索策略,一个容量为65536的数组记录搜索结果。

这样,理论上递归的次数不会超过2^15,平均运行时间应该在纳秒和微秒级。


递归搜索的描述:

如果是甲在取字符,只要找到一个可以赢的取法,甲即可获胜;如果试过所有的取法都不能赢,那么甲就不能获胜。

如果是乙在取字符,只要找到一个可以赢的取法,那么甲即不能获胜;如果试过所有的取法都不能赢,那么甲就可以获胜。


代码如下,核心函数36行。

#include <stdio.h>
#include <iostream>
#include <string>
using namespace std;
class Test {
public:
    static int who (string   word)
    {
        Test test( word );
        return test.can_win( 0, true );
    }
    
    Test( string& word )
    {
        _word = word.data();
        _len = word.size();
        memset( _check, -1, 1 << _len );
    }
    
    char can_win( unsigned short now, bool self )
    {
        char last = 0;
        for( int i = 0; i < _len; i++ ){
            if( !( now & ( 1 << i ) ) ){
                if( _word[i] <= last ){
                    last = 0;
                    break;
                }
                last = _word[i];
            }
        }
        if( last ){
            return self ? 0 : 1;
        }
        for( unsigned short get = 1; get != ( 1 << _len ); get <<= 1 ){
            if( now & get ){
                continue;
            }
            unsigned next = now | get;
            char win = _check[ next ];
            if( win < 0 ){
                win = can_win( next, !self );
                _check[ next ] = win;
            }
            if( self ){
                if( win ){
                    return 1;
                }
            }else{
                if( !win ){
                    return 0;
                }
            }
        }
        return self ? 0 : 1;
    }
    
private:
    const char* _word;
    int _len;
    char _check[65536];
};
//start 提示:自动阅卷起始唯一标识,请勿删除或增加。
int main()
{
    cout<<Test::who("aaaaa")<<endl;   
} 
//end //提示:自动阅卷结束唯一标识,请勿删除或增加。        

吐个槽:英雄会的评奖都是完全黑箱操作,连瞻仰一下最终获奖者的代码的途径都没有。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值