单词博弈的c#求解--答案

昨天把在线编程的第二道题提交了,所以,今天有空坐下来写写第一道题的答案。

逻辑思路:

1、如果甲要取胜,那么对甲来说,面对的字符串,划掉1个字符,必然胜利。

2、如果划掉一个字符,甲不能确定取胜,那么甲有N种划法,假设现在甲面对的字符串长度为N。比如:abcab,那么甲有5种划法,分别是划掉第一个,第二个.......字符。如果甲想取胜,那么,至少有一种划法,划掉一个字符后,交给乙,乙必然失败才行。

3、对于甲划掉的字符,交给乙,对乙来说,面对和甲相同的判断,及需要判断1,2步骤。

 

由上面分析,可以看出,一个简单的递归就可以解决了。下面开写。

首先写第一个函数:

判断字符串,划掉某一个字符,是不是必然胜利

private bool winCheck(string word)
        {
            bool flag = false;
            int count = 0;
            char[] arrword = word.ToCharArray();
            int start = -1;
            for (int i = 1; i < word.Length; i++)
            {
                if (arrword[i] > arrword[i - 1])
                {
                }
                else
                {
                    count++;
                    if (count >= 2)
                    {
                        break;
                    }
                    else
                    {
                        start = i - 1;
                    }
                }
            }
            if (count >= 2)
            {
                flag = false;
                return flag;
            }
            else
            {
                if (count == 0)
                {
                    flag = true;
                }
                else
                {
                    if (start == 0 || start == word.Length - 2)
                    {
                        flag = true;
                    }
                    else
                    {
                        if (arrword[start + 1] > arrword[start - 1] || arrword[start + 2] > arrword[start])
                        {
                            flag = true;
                        }
                        else
                        {
                            flag = false;
                        }
                    }
                }
            }
            return flag;
        }

这个函数逻辑很简单,就是循环以下这个字符串,看看划掉某一个字符串是不是形成一个单调递增的序列。

 

第一步的判断函数写好了。

第二步,由于甲和乙的判断逻辑一样,所以代码可以整合,参数就是word,表示需要判断的字符串,who表示是谁对当前字符串进行判断。

这个判断的逻辑就是:

1、判断当前字符串是否能够必胜。

2、不能够,则遍历所有可能字符串长度N种可能,只要有一种可能,保证自己必胜,那么就划掉这个字符。

 private int CheckAll(string word, int who)
        {
            int result = 0;
            if (winCheck(word))
            {
                result = who;
            }
            else
            {
                for (int i = 0; i < word.Length; i++)
                {
                    string tmp = word.Substring(0, i) + word.Substring(i + 1);
                    int nextwho = who == 0 ? 1 : 0;
                    result = CheckAll(tmp, nextwho);

                    //划掉这个字符,对手必输,所以,不用再往下循环了
                    if (result == who)
                    {
                        break;
                    }
                }
            }
            return result;
        }

ok,到此,所有逻辑完成,看看代码,真的还是比较简洁的。

提交,运行,结果是出来了,不过时间是超过3s了。

看来还需要再优化。

 

问题来了,优化哪里呢?将递归调用转换成迭代,但是分析了下,次数并不会减少啊。

看来此路不通啊。

winCheck函数只循环了一次,看看,问题不在这里。

问题出在递归调用上,浪费了大量时间。

再分析递归调用的逻辑,当一个人划掉一个字符后,交给另一个人去判断,会不会出现很多次,即之前这个字符串已经判断过,并确定了一定是某人胜利?简单分析后,发现出现频率很高,意味着做了很多重复无用功,因此,用一个变量来存储。

我们就选用private Dictionary<string, int> Dic;来存储,字符串,int表示谁胜利,这里还有一个简单的判断,即甲和乙不可能遇到一模一样的字符串(为什么?交给大家想想)

改造下CheckAll函数:

private int CheckAll(string word, int who)
        {
            int result = 0;
            if (winCheck(word))
            {
                result = who;
                if (!Dic.ContainsKey(word))
                {
                    Dic.Add(word, who);
                }
            }
            else
            {
                for (int i = 0; i < word.Length; i++)
                {
                    string tmp = word.Substring(0, i) + word.Substring(i + 1);
                    int nextwho = who == 0 ? 1 : 0;
                    if (Dic.ContainsKey(tmp))
                    {
                        result = Dic[tmp];
                    }
                    else
                    {
                        result = CheckAll(tmp, nextwho);
                        if(!Dic.ContainsKey(tmp))
                        {
                            Dic.Add(tmp, result);
                        }
                    }
                    if (result == who)
                    {
                        break;
                    }
                }
            }
            return result;
        }

现在再运行,输入15位的随机字符串,呵呵,都是0.01秒左右,蛮好,完成。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值