题目详情
输出:1表示甲可以赢,0表示甲不能赢。
例如: 输入 bad, 则甲可以删掉b或者a,剩余的是ad或者bd,他就赢了,输出1。
后记:
甲乙两个人用一个英语单词玩游戏。两个人轮流进行,每个人每次从中删掉任意一个字母,如果剩余的字母序列是严格单调递增的(按字典序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秒内算完还是比较困难的,所以针对题目做特例化优化是一个方向。
欢迎大家在基础上优化提高。