2019独角兽企业重金招聘Python工程师标准>>>

题目在这里。

本来看到这个题的时候,心里想:这个游戏规则很简单,实际要考的本质应该是要你分析给定串的特征,论证这种特征可以保证先手必胜。

于是自己立即尝试了一下简单的情形,便粗略得出以下几个特征:

1、如果在一个已经严格单增串的基础上随便搞上一个字符,无论这个字符如何放,组合出的串都是先手必胜;
2、如果一个串不存在哪怕一个增的字母序列,全是逆序,或字符的重复,如544322110、zyyxtsrr这类,那么串为奇数时,先手必败,否则先手必胜;
3、然后。。。。就没有然后了。。。原谅我这一生放荡不羁智商低,真发现不了更多的规律啊!!!

显然,这么高端大气上档次的数学水平高的解法,咱是搞不定了。
于是,很自然的,只能分析一下游戏的过程,搞一个递归解法出来了,我相信这种有序重复的事情肯定都有递归解法。

解递归问题,我第一做的就是声明一个函数,并赋予这个函数一个意义,这个意义越完美越好,越接近问题的答案越好,我在思想上给予这个意义以支持。比如,游戏要问甲是否胜利,那自然我就声明了一个函数bool win(int player);并赋予它的意义是:player能否战胜对手,返回true就是能战胜对手,否则失败。接着就是根据游戏规则来实现这个递归函数了。

实现递归函数最重要的就是分析一个最小的完备的操作序列集合。这要求认清自己的大脑在解一个东西时的步骤,不要跳跃。

在这个游戏中,甲为先手,那么整个游戏过程肯定是这样的:甲先看看这个序列,琢磨是否可以拿掉某个字符就干掉乙。可以做到,那么甲就胜利了,游戏直接结束。如果不可以,那么甲拿掉其中一个字符,让乙走,这里甲可以拿掉任一字符,为保证思维的有序,就让甲拿第一个好了。这时乙的思维过程和甲一样一样的,也是想一招就干死对方。那么这里我们基本上就已经看到某个重复的东西出现了,暂且放下,继续游戏。假设若干次后,轮到乙操作的时候,可以一招干死甲,我们不能因此就认定甲输了。因为题目问的是甲是否可以胜利,他这么走输了,但是不排除他换个走法必胜,所以这里我们必须允许甲反悔,让游戏从反悔处继续。同样的,也应该允许乙反悔。所以,关键的问题有这么几个:

1、既然都可以反悔,那怎么确定游戏的胜利者,即如何终结递归;
2、如何反悔?即反悔如何具体操作。

下过棋的都知道,如果一个极高水平的人允许低水平的对手随便反悔,最终这个对手都会认输。参考一下那个过程就是:我让你反悔,直到你所有的走法都试尽了,这时候你再输,自然就是输了。用在这里就是这样的:如果选手在输掉时,还可以继续回溯,那就应该回溯,如果不能回溯,那自然就真的输了。是否能回溯的意思就是:在对手拿掉一个字符赢你时,在他走到这一步的操作序列上,有你的操作存在。还有就是在你最高层回溯(即在这个反悔处之前,再也没有你的操作了)时,发现在该处的所有走法都试过了,也不能回溯了。

所以,反悔的具体操作,就是去掉最后一次对手的操作(要反悔,肯定是最后一次对手的操作让你输了,这时你不会接着他继续走棋了,所以最后一次操作是对手的),再接着去掉你的那次操作,选择一个新字符拿掉,继续游戏。

#include <stdio.h>
#include <iostream>
#include <string>
#include <vector>using namespace std;string input;
vector<size_t> seq;    // 用于表示甲乙走棋顺序,按甲乙拿走顺序记录input里被拿走字符的下标
vector<bool> killed;    // 用于表示input里的字符是否被拿掉,该数组与input等长,true表示被拿掉了// player:
// 0表示甲
// 1表示乙// switch_player函数接受0返回1,接收1返回0,返回值用于表示轮到哪位选手
int switch_player(int player);
// win函数判断player是否能打败对方,是则返回true,否则false
bool win(int player);
// 测试拿掉字符之后剩下的字符流是否严格单增,是则返回true,否则false
bool ascending();
// 尝试反悔。player为要反悔的选手。反悔失败则返回false
bool rollback(int player);
// 日志输出
void print_log(int player);class Test {
public:static int who (string   word){input = word;seq.clear();killed.assign(input.size(), false);if (win(0)) {return 1;}return 0;}
};
//start 提示:自动阅卷起始唯一标识,请勿删除或增加。
int main()
{   cout<<Test::who("Test")<<endl;
}
//end //提示:自动阅卷结束唯一标识,请勿删除或增加。int switch_player( int player )
{if (player == 0)return 1;elsereturn 0;
}bool win(int player)
{size_t count = killed.size();for (size_t n = 0; n < count; n++) {if (killed[n]) {continue;}else {killed[n] = true;// 测试假如拿掉一个字符的话是否明显打败对方// 是的话,则直接以true胜利结束函数if (ascending()) {seq.push_back(n);print_log(player);return true;}else {killed[n] = false;continue;}}}// 拿掉任何字符都不能明显打败对方,则从长计议for (size_t n = 0; n < count; n++) {if (killed[n]) {continue;}killed[n] = true;seq.push_back(n);if (win(switch_player(player))) {    // 拿掉一个字符后被对方打败,则player肯定要反悔if (rollback(player))continue;else return false;}else {// 拿掉一个字符后,剩下的也能赢对手,// 则player高兴坏了,直接以true胜利结束函数return true;}}// 能跑到这里,只能说明player反悔到了头,// 所有字符都拿过一遍,均不能击败对手,以false失败告终return false;
}bool ascending()
{char pre_char;bool pre_used = false;size_t count = killed.size();for (size_t n = 0; n < count; n++){if (killed[n]) {continue;}if (pre_used) {if (pre_char >= input[n]) {return false;}else {pre_char = input[n];}}else {pre_used = true;pre_char = input[n];}}return true;
}bool rollback(int player)
{size_t count = killed.size();// player要反悔。player要反悔的情况,肯定是对手能打败他。if ((seq.size() % 2) == player && seq.size() >= 2) {killed[ seq.back() ] = false;seq.pop_back();    // 清空对手的操作killed[ seq.back() ] = false;seq.pop_back(); // 清空自己最后一次导致对手胜利的操作return true;}return false;
}void print_log(int player)
{if (player == 1) {std::cout << "甲失败 [ ";}else {std::cout << "甲获胜 [ ";}for (size_t num = 0; num < seq.size(); num++) {std::cout << seq[num] << " ";}std::cout << "]\n";
}

当然,这个题目我挑战失败了,哈哈哈!系统告诉我3s之内没能解出答案。这很显然,我这个递归没有做任何解法上的优化,是严格的反映着游戏的基本过程。当然这个递归解法对10个字符以内的还可以接受吧,15个及以上确实太慢了。

当然,虽然我这个代码没有挑战成功,但我相信这个严格对应游戏完整过程的解法有很好的优化空间,比如说:

1、如果你有高端大气上档次的数学公式,可以直接看出某串是否能胜利,那把这个公式替换到我的ascending函数体里就ok了,不用改其他部分。
2、如果做不到完全判断任意串是否能胜利,能做到某些特殊情况的判断也好,就如我最开始提到的那几个规律,把这些规律放到ascending函数里,也能加速判断胜负的过程。也不用改其他部分。
3、还可以做某些缓存工作,比如某些串之前试过必然是个啥结果,以后再判断就不用重复判断了,也直接塞ascending函数里,不用改其他部分。

虽然说的很好听,但我实在是想不到啥好规律,只是在写这个文章的时候突然想到一个很重要的规律:如果拿掉一个严格单增串(当然是整个输入串里的一部分)里最大字符前面的任意字符有个胜负判断,那拿掉任何该严格单增串里最大字符前除了刚拿掉的这个字符外的字符,和刚才的胜负一样,这样应该可以跳过不少需要判断的情况。

望赐教。规律何在!

转载于:https://my.oschina.net/zhoubaojing/blog/178669

庞果网一道题(字符博弈)的一点想法相关推荐

  1. 关于庞果网数组排序的问题

    昨天在庞果网看了个题目,难度只有两星(最高为五星),看似简单,120分钟内却没有做出来,深受打击!想了一晚上,终于感觉能给出个可用的算法了.题目如下:   题目并不要求排序, 只是让求出如果排序最少需 ...

  2. 庞果网之建立信号基站

    题目详情 要建立一个信号基站服务n个村庄,这n个村庄用平面上的n个点表示.假设基站建立的位置在(X,Y),则它对某个村庄(x,y)的距离为max{|X – x|, |Y – y|}, 其中| |表示绝 ...

  3. 庞果网之杨辉三角的变形

    题目详情 1 1   1  1 1  2   3  2  1 1  3  6   7  6  3  1 以上三角形的数阵,第一行只有一个数1, 以下每行的每个数,是恰好是它上面的数,左上的数和右上数等 ...

  4. 庞果网之字符串的完美度

    题目详情 我们要给每个字母配一个1-26之间的整数,具体怎么分配由你决定,但不同字母的完美度不同, 而一个字符串的完美度等于它里面所有字母的完美度之和,且不在乎字母大小写,也就是说字母F和f的完美度是 ...

  5. 庞果网练习题——魔法

    庞果网练习题--魔法 自己做着玩的,欢迎指正.指点.一起讨论. 题目详情 你拥有3种魔法,可以用第一种魔法把 a 克的沙子变成 b 克金属,可以用第二种魔法把 c 克金属变成 d 克金子,可以用第三种 ...

  6. 庞果网之寻找直方图中面积最大的矩形

    题目详情 给定直方图,每一小块的height由N个非负整数所确定,每一小块的width都为1,请找出直方图中面积最大的矩形. 如下图所示,直方图中每一块的宽度都是1,每一块给定的高度分别是[2,1,5 ...

  7. 回文字符串——庞果网

    题目依旧是来自庞果网. 题目详情: 回文字符串是指从左到右和从右到左相同的字符串,现给定一个仅由小写字母组成的字符串,你可以把它的字母重新排列,以形成不同的回文字符串. 输入:非空仅由小写字母组成的字 ...

  8. 人才招聘新趋势:垂直性的社交网络——pongo网(庞果网)CEO李炯明专访

    记者 / 长卿 近日,国内专业IT人才招聘服务公司Careerfocus联合全球最大中文IT社区CSDN推出了IT行业细分的招聘求职网站pongo(庞果网),力图通过搜索引擎,垂直型社交网络构建IT行 ...

  9. 关于《关于一道C#上机题的一点想法》

    看了<关于一道C#上机题的一点想法>和<泛型委托>两篇文章,深有感触,还是关于下面这道题: 题目:17个人围成一圈,从第一个人开始报数,报到3的退出,一直到剩下最后一个人,用面 ...

  10. 关于标签系统的又一点想法。

    前段时间,写过一篇<关于标签系统的一点想法.>.但其实没有谈到里面的内容,是有一部分来自与刘鑫老师的聊天,当时他给了我许多肯定,也是让我觉得记录下来很有必要的原因. 前一篇里没有提到,我跟 ...

最新文章

  1. hadoop磁盘空间不均衡的解决办法
  2. pb连接多个数据库 有关问题2
  3. PHP面试题:使用PHP描述快速排序算法,对象可以是一个数组?
  4. linux防火墙常用缩写,Linux iptables常用防火墙规则
  5. IOProcess基础知识
  6. c++ 获得linux进程内存大小,C/C++获取进程常驻内存大小(get the process resident set size )...
  7. Unity NGUI 组件简介
  8. paypal 接口开发 的官方文档 html变量的定义 国别代码 货币代码
  9. vue-router路由文档详解
  10. win11 外接键盘个别按键(win,alt)失灵
  11. 新浪tcn短网址短链接在线生成器推荐
  12. VS 2017安装教程
  13. C64x+ 与 C64x Cache 区别
  14. Ubuntu镜像名称解释
  15. 远程服务器 检索{00024500-0000-0000-C000-000000000046}组件失败 80080005 服务器运行失败 解决方案
  16. 视频教程-uni-app实战仿微信app开发-Webapp
  17. 跨考西北工业大学计算机专硕,西工大计算机专硕400+上岸学长经验分享
  18. 计算机专业答辩开场白,毕业论文答辩开场白
  19. [案例4-8]模拟物流快递系统程序设计
  20. swiper.js显示指定图片

热门文章

  1. 免费CMS系统的广告如何去掉
  2. 用php实现mongoDB的基本操作
  3. 键盘上各种特殊符号的英文读法
  4. Dijkstra算法详解:
  5. 全新的Smultron 12已发布:简单好用、功能强大、优雅简洁
  6. M1芯片Macbook最简单从11.3降级到11.2.3教程
  7. 通过JS制作一个简易数码时钟
  8. HDU 1711 Number Sequence (KMP)
  9. 属性,初始化,类别,协议
  10. android的wake_lock介绍