【搜索】速算游戏

第 1 题 速算游戏
 
 
源程序名 fun.pas|c|cpp
输入文件名 fun.in
输出文件名 fun.out
时间限制 1s/testcase
空间限制 32MB
 
问题描述
jyx和cyy打赌,比谁24点算得快,算得慢的那个人请客。24点的规则是这样的:给定4
个1..9的整数,用括号改变运算顺序,通过加、减、乘、除通的一系列运算,得到整数24,
注意所有中间结果必须是整数(例如(2*2)/4是允许的,而2*(2/4)是不允许的)。为了赢得
这个比赛,请写一个程序帮助我作弊,快速地计算出24点。
 
输入数据
一行 4 个整数,为给定的 4 个数字。输入数据保证有解。
 
输出数据
一行,以字符串的形式输出结果,注意将每一步的运算的括号补齐(例如(3+5)+6和
3*(5+6))如果有多种解答,输出字典顺序最小的一个。
 
样例输入
2 3 5 7
 
样例输出

(((3*5)+2)+7)



容易想到要生成全排列,但是又容易被括号误导。

但是我们来单独讨论一下括号,无非就是下面三种情况。

(((a?b)?c)?d)、(((a?b)?(c?d))、(a?(b?(c?d)))

但是考虑到括号的ASCII码是最小的,因此第三种可以果断排除,

因为它们可以有完全相同的运算,但是明显第一种比第三种的字典序小。


一开始差点打错,差点按照+、-、*、/来了。注意/要单独考虑,因为不能有除不尽的情况。


ZQZ犯了一个错,他先生成数字的全排列,再生成符号的全排列,因此不能保证字典序最小。

所以必须间隔搜索。


#include <cstdio>
#include <string>
#include <cstring>
#include <algorithm>
#include <cstdlib>
using std::sort;

const char hash[5] = {0,'*','+','-','/'};
long num[5];
long stack1[20];
long stack2[20];

long getint()
{
	long rs=0;bool sgn=1;char tmp;
	do tmp = getchar();
	while (!isdigit(tmp)&&tmp!='-');
	if (tmp=='-'){tmp=getchar();sgn=0;}
	do rs=(rs<<3)+(rs<<1)+tmp-'0';
	while (isdigit(tmp=getchar()));
	return sgn?rs:-rs;
}

long calc(long a,long b,long c)
{
	switch (c)
	{
		case 1:
			return a*b;
		case 2:
			return a+b;
		case 3:
			return a-b;
		case 4:
			if (!(a % b))
				return a/b;
			else
				return -0x3f3f3f3f;
	}
	return -0x3f3f3f3f;
}

bool used[5];

void dfs(long u,bool o)
{
	if (u == 8)
	{
		long rs = calc(stack1[1],stack1[3],stack2[2]);
		if (rs == -0x3f3f3f3f) return;
		rs = calc(rs,stack1[5],stack2[4]);
		if (rs == -0x3f3f3f3f) return;
		rs = calc(rs,stack1[7],stack2[6]);
		if (rs == -0x3f3f3f3f) return;

		if (rs == 24)
		{
			printf("(((%ld%c%ld)%c%ld)%c%ld)",stack1[1],hash[stack2[2]],stack1[3],hash[stack2[4]],stack1[5],hash[stack2[6]],stack1[7]);
			exit(0);
		}
		return;
	}
	if (o)
	{
		for (long i=1;i<5;i++)
		{
			if (!used[i])
			{
				stack1[u] = num[i];
				used[i] = u;
				dfs(u+1,!o);
				used[i] = 0;
			}
		}
	}
	else
	{
		for (long i=1;i<5;i++)
		{
			stack2[u] = i;
			dfs(u+1,!o);
		}
	}
}

void dfs2(long u,bool o)
{
	if (u == 8)
	{
		long rs1 = calc(stack1[1],stack1[3],stack2[2]);
		if (rs1 == -0x3f3f3f3f) return;
		long rs2 = calc(stack1[5],stack1[7],stack2[6]);
		if (rs2 == -0x3f3f3f3f) return;
		long rs = calc(rs1,rs2,stack2[4]);
		if (rs == -0x3f3f3f3f) return;

		if (rs == 24)
		{
			printf("((%ld%c%ld)%c(%ld%c%ld))",stack1[1],hash[stack2[2]],stack1[3],hash[stack2[4]],stack1[5],hash[stack2[6]],stack1[7]);
			exit(0);
		}
		return;
	}
	if (o)
	{
		for (long i=1;i<5;i++)
		{
			if (!used[i])
			{
				stack1[u] = num[i];
				used[i] = 1;
				dfs2(u+1,!o);
				used[i] = 0;
			}
		}
	}
	else
	{
		for (long i=1;i<5;i++)
		{
			stack2[u] = i;
			dfs2(u+1,!o);
		}
	}
}

int main()
{
	freopen("fun.in","r",stdin);
	freopen("fun.out","w",stdout);

	num[1] = getint();
	num[2] = getint();
	num[3] = getint();
	num[4] = getint();
	sort(num+1,num+5);

	dfs(1,true);
	dfs2(1,true);

	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值