2015-08-25

24点游戏,就是选4个数,对其运用加减乘除,得到24,可以使用括号。关于24点游戏的解法,《编程之美》上面说得比较清楚,我这里直接使用第二种解法。这里在合并S集的时候是不应该像书上说的去重的,因为虽然说产生的数一样,但是他们是不同的计算的方式产生的,如果这个时候去重会导致得不出正确的解法个数,正确的去重应该是在最后统计S[15]中24的个数时。下面是运行结果:

#include <iostream>
#include <vector>
#include <set>
#include <algorithm>
#include <iterator>
#include <string>
#include <math.h>

using namespace std;
const double threHold = 1E-6;

struct Node
{
	double value;
	string exp;
	Node(double v, string s) :value(v), exp(s){}
	friend bool operator < (const Node &node1, const Node &node2)
	{
		return node1.value < node2.value;
	}
};

class PointGameSolver
{
public:
	PointGameSolver(initializer_list<double> li) :init(li)
	{
		S = new multiset<Node>[static_cast<int>(pow(2, init.size()))];
	}
	int getResult(set<string>& ans)
	{
		ans.clear();
		calc();
		return check(ans);
	}
	~PointGameSolver()
	{
		delete[] S;
	}
private:
	int check(set<string>& result);
	multiset<Node> setS(int i);
	multiset<Node> getUnion(multiset<Node> a, multiset<Node> b);
	multiset<Node> fork(multiset<Node> a, multiset<Node> b);
	void calc();
	
	multiset<Node>  *S;
	vector<double> init;
};

int PointGameSolver::check(set<string>& result)
{
	int count = 0;
	multiset<Node> ans = S[static_cast<int>(pow(2, init.size()) - 1)];
	for (auto it = ans.begin(); it != ans.end(); ++it)
	{
		if ((it->value - 0) > threHold && fabs(it->value - 24) < threHold)
		{
			count++;
			result.insert(it->exp);
		}
	}
	return result.size();
}
multiset<Node> PointGameSolver::setS(int i)
{
	if (!S[i].empty())
		return S[i];
	for (int x = 1; x < i; ++x)
	{
		if ((x & i) == x)
			S[i] = getUnion(S[i], fork(setS(x), setS(i - x)));
	}
	return S[i];
}
multiset<Node> PointGameSolver::getUnion(multiset<Node> a, multiset<Node> b)
{
	multiset<Node> result;
	copy(a.begin(), a.end(), inserter(result, result.begin()));
	copy(b.begin(), b.end(), inserter(result, result.begin()));
	return result;
}
multiset<Node> PointGameSolver::fork(multiset<Node> a, multiset<Node> b)
{
	if (a.empty())
		return b;
	if (b.empty())
		return a;
	multiset<Node> result;
	for (auto ita = a.begin(); ita != a.end(); ++ita)
	{
		for (auto itb = b.begin(); itb != b.end(); ++itb)
		{
			result.insert(Node(ita->value + itb->value, "(" + ita->exp + "+" + itb->exp + ")"));
			result.insert(Node(ita->value * itb->value, "(" + ita->exp + "*" + itb->exp + ")"));
			result.insert(Node(ita->value - itb->value, "(" + ita->exp + "-" + itb->exp + ")"));
			result.insert(Node(itb->value - ita->value, "(" + itb->exp + "-" + ita->exp + ")"));
			if (!((fabs(ita->value - 0) < threHold)))
			{
				result.insert(Node(ita->value / itb->value, "(" + ita->exp + "/" + itb->exp + ")"));
			}
			if (!((fabs(itb->value - 0) < threHold)))
			{
				result.insert(Node(itb->value / ita->value, "(" + itb->exp + "/" + ita->exp + ")"));
			}

		}
	}
	return result;
}
void PointGameSolver::calc()
{
	size_t n = init.size();
	for (size_t i = 0; i < n; ++i)
	{
		S[static_cast<int>(pow(2, i))].insert(Node(init[i], to_string((int)init[i])));
	}
	for (size_t i = 1; i < pow(2, n); ++i)
	{
		S[i] = setS(i);
	}
}

bool isValid(int *a, int n)
{
	for (int i = 0; i < n; ++i)
	{
		if (a[i] < 1 || a[i] > 10)
			return false;
	}
	return true;
}
int _tmain(int argc, _TCHAR* argv[])
{
	int data[4];
	while (1)
	{
		cout << "请输入4个数(1-10,空格隔开):";
		int i = 0;
		while (cin >> data[i++])
		{
			if (i == 4)
				break;
		}
		if (cin && isValid(data, 4))
		{
			PointGameSolver pgs({ (double)data[0], (double)data[1], (double)data[2], (double)data[3] });
			set<string> ans;
			int count = pgs.getResult(ans);
			if (!count)
			{
				cout << "no solution\n";
			}
			else
			{
				cout << "total solutions :" << count << endl;
				for_each(ans.begin(), ans.end(), [](const string &s) {cout << s << endl; });
			}
		}
		else
			cout << "invalid input \n";
		cout << "\n";

		cout << "continue?(y/n):";
		if (!cin)
			cin.clear();
		cin.ignore(numeric_limits<streamsize>::max(), '\n');
		string str;
		cin >> str;
		if (str != "Y" && str != "y")
			break;
	}

	return 0;
}

竟然有人看到了文末,那就扯点别的。这是UCloud的面试题,昨晚接到UCloud面试官的电话,简单说了下他们是做网络虚拟化的,问有没有兴趣。随意聊了一下,然后就在我准备接受一番血虐的时候,他直接就给我整个这个题,太直接了好嘛,有一种dota里面的“生死看淡,不服就干”的味道。然后我当然就查资料了,发现竟然是编程之美上面的,然后看了下思路,顺着书上的框架写好代码,完工之后才发现还要输出所有解。想了一会,之前想到甚至用tuple来保存表达式,后来想到还是直接string简单点,把multiset,换成了multiset了,Node里面包括了值和产生此值的表达式,看起来也还算不错。



blog comments powered by Disqus