使用了深度搜索、深度优先遍历多叉树等方法,最终输出 先手 必胜策略下的每一步状态转移,奇数步对应先手,偶数步对应后手
#include <iostream>
#include <vector>
using namespace std;
struct Sta
{
int pos; // 从第几个位置取,从0开始计数
int len; // 取几个数,1或者2
};
struct TreeNode
{
std::vector<TreeNode *> children;
std::vector<int> status;
};
// 输出当前状态可实施的所有策略
vector<Sta> genAllStategy(const vector<int> & status)
{
vector<Sta> res;
// 先生成所有 len为1的策略
for (int i = 0; i < status.size(); i++)
{
if (status[i] != 0)
{
Sta s;
s.pos = i;
s.len = 1;
res.push_back(s);
}
}
// 生成所有 len为 2 的策略
for (int i = 0; i < status.size() - 1; i++)
{
if (status[i] != 0 && status[i + 1] != 0)
{
Sta s;
s.pos = i;
s.len = 2;
res.push_back(s);
}
}
return res;
}
// 外部保存 s 合法
vector<int> apply(const vector<int> & status, Sta s)
{
vector<int> res = status;
auto pos = s.pos;
if (s.len == 1)
{
res[pos] = 0;
}
else
{
res[pos] = res[pos + 1] = 0;
}
return res;
}
bool checkStatusEnd(const vector<int> & status)
{
for (auto i : status)
{
if (i != 0)
{
return false;
}
}
return true;
}
vector<Sta> steps;
//int counter = 0;
TreeNode treeHead;
// currPlayer 为0 表示 xianshou
// 本函数专门搜索 是否有先手必赢的策略
bool search(vector<int> status, bool currPlayer, int depth, TreeNode * trParent)
{
auto strag = genAllStategy(status);
if (!currPlayer)
{
bool result = false;
// 如果是先手下, 任意一种子路径导致true都应该返回true
// 因为导致true的条件是 所有子路径全都返回true
for (const auto s : strag)
{
//steps[counter] = s;
//counter++;
// res是新的状态
vector<int> res = apply(status, s);
TreeNode * tn = new TreeNode;
tn->status = res;
trParent->children.push_back(tn);
// 是否到达终局
bool bEnd = checkStatusEnd(res);
if (bEnd)
{
//std::cout << "depth:" << depth << " S-xianshou: sta pos " << s.pos << " str len " << s.len << std::endl;
result = true;
break;
}
else
{
// 继续搜索
auto temp = search(res, !currPlayer, depth+1, tn);
if (temp == false)
{
// 说明当前策略s不能保证 必赢,清空所有的模拟下法
// std::cout << "depth: F: " << " sta pos " << s.pos << " str len " << s.len << std::endl;;
trParent->children.pop_back();
}
else
{
std::cout << "depth:" << depth << " S-xianshou: sta pos " << s.pos << " str len " << s.len << std::endl;
result = true;
break;
}
}
}
return result;
}
else
{
bool result = true;
// 后手下, 任意一种子路径导致false都应该返回false
for (const auto s : strag)
{
vector<int> res = apply(status, s);
TreeNode * tn = new TreeNode;
tn->status = res;
trParent->children.push_back(tn);
// 是否到达终局
bool bEnd = checkStatusEnd(res);
if (bEnd)
{
// 此路不通
trParent->children.pop_back();
result = false;
break;
}
else
{
// 继续搜索
auto temp = search(res, !currPlayer, depth + 1, tn);
if (temp == false)
{
result = false;
break;
}
else
{
std::cout << "depth:" << depth << " S-houshou: sta pos " << s.pos << " str len " << s.len << std::endl;
}
}
}
return result;
}
}
void outputStatus(const std::vector<int> & status)
{
for (auto i : status)
{
std::cout << i << " ";
}
std::cout << std::endl;
}
void deepTraverse(TreeNode * trParent,int depth = 0)
{
if (trParent != NULL)
{
outputStatus(trParent->status);
for (auto c : trParent->children)
{
for (int i = 0; i < depth+1; i++)
{
std::cout << "---- ";
}
deepTraverse(c, depth+1);
}
}
}
int main()
{
vector<int> status = { 1,1,1,1,1 };
treeHead.status = status;
auto res = search(status, 0, 0, &treeHead);
std::cout << " res is " << res << std::endl;
deepTraverse(&treeHead);
// TODO: 释放 树 对应的内存
return 0;
}