庞果网英雄会第一届在线编程大赛:单词博弈
题目如下
甲乙两个人用一个英语单词玩游戏。两个人轮流进行,每个人每次从中删掉任意一个字母,如果剩余的字母序列是严格单调递增的(按字典序a < b < c <....<z),则这个人胜利。两个人都足够聪明(即如果有赢的方案,都不会选输的方案 ),甲先开始,问他能赢么?
输入: 一连串英文小写字母,长度不超过15,保证最开始的状态不是一个严格单增的序列。
输出:1表示甲可以赢,0表示甲不能赢。
例如: 输入 bad, 则甲可以删掉b或者a,剩余的是ad或者bd,他就赢了,输出1。
又如: 输入 aaa, 则甲只能删掉1个a,乙删掉一个a,剩余1个a,乙获胜,输出0。
分析:由于假设了两人足够聪明,即轮到某个人删除字母的时候,他一定会选对自己最有利的选择。例如轮到甲删除的时,甲想赢得游戏,那么一定存在一种选择使得甲删除该字母后,无论乙怎么选择都会导致甲赢,否则甲就会输。
这一题可以采用dfs+记录表的方法,利用两个记录表(map)分别记录甲乙两人已经操作过的单词子串以防止计算重复子问题(例如对于单词abcd,下面两种情况下对单词子串cd有重复计算,甲删除a,乙再删除b,然后甲要对单词cd进行删除;甲删除b,乙删除a,甲对单词cd进行删除)。
记录表amap[s] = true 表示字符串s由甲来删除时,甲会赢得游戏,= false则表示甲会输
记录表bmap[s] = true 表示字符串s由乙来删除时,甲会赢得游戏,= false则表示甲会输(注意是甲是否会赢得游戏)
class Test { public: typedef map<string, bool> Map; static int who (string word) { //用map保存子问题,防止重复计算 //amap[s]表示字符串s由甲操作时甲能否获胜 //bmap[s]表示字符串s由乙操作时甲能否获胜 Map amap, bmap; return (int)dfs(word, 1, amap, bmap); } private: //判断字符串是否严格递增 static bool isIncrease(string &s) { int len = s.size(); for(int i = 1; i < len; i++) if(s[i] <= s[i-1])return false; return true; } //id == 1表示接下来由甲操作,否则是乙 //返回true表示甲会赢得游戏,返回false则甲会输 static bool dfs(string &s, bool id, Map &amap, Map &bmap) { if(isIncrease(s)) { if(id == 0) return true; else return false; } int len = s.size(); for(int i = 0; i < len; i++) { string subs = s; subs.erase(i,1); bool tmp; if(id == 0) {//由乙操作时,要所有情况返回true,即所有情况乙都会输,甲就赢得游戏 if(bmap.find(subs) == bmap.end()) { tmp = dfs(subs, id^true, amap, bmap); bmap[subs] = tmp; } else tmp = bmap[subs]; if(tmp == false)return false; } else {//由甲操作时,只要一种情况返回true,甲就赢得游戏 if(amap.find(subs) == amap.end()) { tmp = dfs(subs, id^true, amap, bmap); amap[subs] = tmp; } else tmp = amap[subs]; if(tmp == true)return true; } } if(id == 0) return true; else return false; } };
调用Test::who(sting word) 来判断对于单词word甲是否会赢
【版权声明】转载请注明出处:http://www.cnblogs.com/TenosDoIt/p/3485090.html