编程之美---NIM游戏

使用了深度搜索、深度优先遍历多叉树等方法,最终输出 先手 必胜策略下的每一步状态转移,奇数步对应先手,偶数步对应后手

#include 
#include 

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;
}

你可能感兴趣的:(个人作品,算法,C++,编程之美)