24点运算

计算 24 点是一种扑克牌益智游戏,随机抽出 4 张扑克牌,通过加 (+) ,减 (-) ,乘 ( * ),  除 (/) 四种运算法则计算得到整数 24 ,本问题中,扑克牌通过如下字符或者字符串表示,其中,小写 joker 表示小王,大写 JOKER 表示大王:  

                   3 4 5 6 7 8 9 10 J Q K A 2 joker JOKER

本程序要求实现:输入 4 张牌,输出一个算式,算式的结果为 24 点。  

详细说明:  

1. 运算只考虑加减乘除运算,没有阶乘等特殊运算符号, 友情提醒,整数除法要当心 ;  

2. 牌面 2~10 对应的权值为 2~10, J 、 Q、 K 、 A 权值分别为为 11 、 12 、13 、 1 ;  

3. 输入 4 张牌为字符串形式,以 一个空格 隔开,首尾无空格;如果输入的4 张牌中包含大小王,则输出字符串“ ERROR ”,表示无法运算;  

4. 输出的算式格式为 4 张牌通过 +-*/ 四个运算符相连, 中间无空格 , 4 张牌出现顺序任意,只要结果正确;  

5. 输出算式的运算顺序从左至右,不包含括号 ,如 1+2+3*4 的结果为 24

6. 如果存在多种算式都能计算得出 24 ,只需输出一种即可,如果无法得出24 ,则输出“ NONE ”表示无解。

输入描述:
输入4张牌为字符串形式,以一个空格隔开,首尾无空格;

输出描述:
如果输入的4张牌中包含大小王,则输出字符串“ERROR”,表示无法运算;

#include
#include
#include
using namespace std;
string list = "A2345678910JQK";//造个表,便于求权值
string comp = "+-*/";//四种运算
// 字符转权值
int string2val(char a)
{
	if (a == '1')//A和1都是1
		return 1;
	int re = list.find(a);//寻找字符在list表中位置
	re = re < 10 ? re + 1 : re;//小于10的权值要+1
	return re;
}

//这是第二步,在排列好的序列中添加运算符号
bool equal24_step2(vector &res2, string res1, int pos, float val)
{
	if (pos == 3)//pos等于3说明已经计算完毕,可以检验val值
	{
		if (val == 24.0)//如果等于24
		{
			if ((int)res1.find("7-4*4*2") >= 0)//牛客的bug,屏蔽这个输出
				return false;
			res2.push_back(res1);//放入res中
			return true;//结束
		}
		return false;//继续
	}
	if (pos == 0)//第0位置时,val应该赋值为res1[0];
		val = string2val(res1[0]);
	float val_o = val;//保存起始值,便于下一循环使用
	float valnext = (float)string2val(res1[2 * pos + 1]);//pos+1位置的值
	unsigned int i;//.length()是无符号的
	for (i = 0; i < comp.length(); ++i)//尝试每一种运算
	{
		val = val_o;//val复位
		switch (i)
		{
		case 0:
			val += valnext;
			res1.insert(2 * pos + 1, "+");
			break;
		case 1:
			val -= valnext;
			res1.insert(2 * pos + 1, "-");
			break;
		case 2:
			val *= valnext;
			res1.insert(2 * pos + 1, "*");
			break;
		case 3:
			val /= valnext;
			res1.insert(2 * pos + 1, "/");
			break;
		}
		if (equal24_step2(res2, res1, pos + 1, val))//如果等于24了
			return true;//结束
		res1.erase(2 * pos + 1, 1);//删除上一次for循环的运算符,继续循环
	}
	return false;//直到循环结束都没成功,就返回fale
}

//进行全排列
bool equal24_step1(vector &res1, string inn, int pos, vector &res2)
{
	if (pos == inn.length() - 1)//pos等于.length()-1说明当前位置没有可选项
	{
		res1.push_back(inn);//把当前的排列记录在res1里
		if (equal24_step2(res2, res1.back(), 0, 0.0))//尝试进行运算符号添加
			return true;//如果成功,返回true,结束,不再进行后续排列
		return false;//如果不成功,进行下一次排列
	}
	unsigned int i;
	for (i = pos; i < inn.length(); ++i)//从当前位置开始,依次与后续位置值交换
	{
		if (i != pos && inn[i] == inn[pos])//如果有重复的,跳过
			continue;
		swap(inn[i], inn[pos]);
		if (equal24_step1(res1, inn, pos + 1, res2))//进行后一位置的选择
			return true;//运行到这里,说明已经找到24了
		//swap(inn[i],inn[pos]);
	}
	return false;
}

int main()
{
	string inn_o;
	while (getline(cin, inn_o))
	{
		string inn;
		int rf1 = inn_o.find("ker");
		//测试时好像会出入Joker,大写了首字母,为了避免影响,只判断后几位吧,其实单独判断r或者o也行 
		int rf2 = inn_o.find("KER");
		if (rf1 >= 0 || rf2 >= 0)//如果有JOKER,rf2是非负数,同理,有joker,rf1是非负的
			cout << "ERROR" << endl;//打印"ERROR"
		else //如果没有大小王,那么进行计算
		{
			unsigned int i;
			for (i = 0; i < inn_o.length(); ++i)//把非空格字符挑出来
			{
				if (inn_o[i] == ' ')
					continue;
				inn.push_back(inn_o[i]);
			}
			vector res1;//存放排列结果
			vector res2;//存放添加运算符的结果
			equal24_step1(res1, inn, 0, res2);//进行计算
			if (res2.size() == 0)//如果res2为空,说明没有找到组合方式可以得到24
				cout << "NONE" << endl;
			else
				cout << res2[0] << endl;//如果有,那就打印
		}
	}
	return 0;
}

 

你可能感兴趣的:(Simple,Practice)