计算24表达式计数问题

mathe 2005-01-08 08:14:48
我们知道,在算24游戏中,我们是通过给定4个数字,要求通过+,-,*,/,以及(),得到24
比如给定4个数字a,b,c,d,要求大家通过一些表达式,比如
(a+b)-c*d, a+(b-c*d),a*b-c-d
等等
上面的这些表达式种,有些表达式对于无论a,b,c,d取任何值,表达式的结果总是相等的
比如
(a+b)-c*d和a+(b-c*d)总是取相同的值
这些表达式我们认为是等价的
请问4个数字构成的相互不等价的表达式总共有多少个
...全文
433 20 打赏 收藏 转发到动态 举报
写回复
用AI写文章
20 条回复
切换为时间正序
请发表友善的回复…
发表回复
jyk1970 2005-02-02
  • 打赏
  • 举报
回复
随机选四个数(1..10)之间,经过加减乘除(浮点运算)后结果为24.
1..10之间可以随机重复数字.如可以选4个5.
http://community.csdn.net/Expert/topic/2735/2735514.xml?temp=.511944
共 1737 个解
languagec 2005-02-02
  • 打赏
  • 举报
回复
mathe 2005-01-28
  • 打赏
  • 举报
回复
其实只要看c_main一个函数就可以了。
前面的代码定义一个factor_num类用于有理数计算。
show()是用来显示一个表达式的,避免了不必要的括号。
函数c24是c_main的一个封装,因为存在某些数据相同时,不同的表达式数目要减少
还有上面的代码排版有问题,最好弄到VC里面自动排版一下再看
FengYuanMSFT 2005-01-27
  • 打赏
  • 举报
回复
http://community.csdn.net/Expert/topic/3671/3671564.xml?temp=.6485865
shines77 2005-01-26
  • 打赏
  • 举报
回复
mark一下
laughcry2002 2005-01-26
  • 打赏
  • 举报
回复
太长了。。呵呵,看不完啊。。。
mathe 2005-01-21
  • 打赏
  • 举报
回复
#define elems(x) (sizeof(x)/sizeof(x[0]))

void c_main(INT input[],int mask,INT result)
{
int total=0;
int i;
factor_num r1,r2,r;
for(i=0;i<elems(table);i++){
int op=table[ i]&63;
int left=table[ i]>>6;
int g=left>>4;
int pl=left&15;
int pattern=pm[pl]&mask;
int j;
for(j=0;j<24;j++){
if(pattern&(1<<j)){
short elem=(j+g*24)*64+op;
expression t(elem);
short op1=t.first_op();
short op2=t.second_op();
short op3=t.third_op();
short gtype=t.graph_type();
short order=t.num_order();
factor_num aa=factor_num(input[o0[order]],1);
factor_num bb=factor_num(input[o1[order]],1);
factor_num cc=factor_num(input[o2[order]],1);
factor_num dd=factor_num(input[o3[order]],1);
OperatorFun fun1=funs[op1];
OperatorFun fun2=funs[op2];
OperatorFun fun3=funs[op3];
switch(gtype){
case 0:
r1=fun1(aa,bb);
r2=fun3(cc,dd);
r=fun2(r1,r2);
break;
case 1:
r1=fun1(aa,bb);
r2=fun2(r1,cc);
r=fun3(r2,dd);
break;
case 2:
r1=fun2(bb,cc);
r2=fun1(aa,r1);
r=fun3(r2,dd);
break;
case 3:
r1=fun2(bb,cc);
r2=fun3(r1,dd);
r=fun1(aa,r2);
break;
case 4:
r1=fun3(cc,dd);
r2=fun2(bb,r1);
r=fun1(aa,r2);
break;
}
if(equal_num(r,result)){
show(input,t);
printf("\t");
total++;
}
}
}
}
if(total)printf("\n");
}

void c24(INT s1,INT s2,INT s3,INT s4,INT r){
INT input[4];
int i,j;
input[0]=s1;input[1]=s2;input[2]=s3;input[3]=s4;
for(i=0;i<4;i++){
for(j=i+1;j<4;j++){
if(input[j]<input[ i]){
INT temp=input[j];
input[j]=input[ i];
input[ i]=temp;
}
}
}
if(input[0]==input[1]){//a==b
if(input[1]!=input[2]){
if(input[2]!=input[3]){//only a==b
INT temp=input[2];
input[2]=input[0];
input[0]=temp;
temp=input[3];
input[3]=input[1];
input[1]=temp;
c_main(input,mask_cd,r);
}else{//a==b,c==d
c_main(input,mask_ab_cd,r);
}
}else if(input[2]!=input[3]){//a==b==c!=d
INT temp=input[0];
input[0]=input[3];
input[3]=temp;
c_main(input,mask_bcd,r);
}else{//a==b==c==d
c_main(input,mask_abcd,r);
}
}else{//a!=b
if(input[1]==input[2]){
if(input[2]!=input[3]){//b==c
INT temp=input[3];
input[3]=input[1];
input[1]=temp;
c_main(input,mask_cd,r);
}else{//b==c==d
c_main(input,mask_bcd,r);
}
}else{
if(input[2]==input[3]){//c==d
c_main(input,mask_cd,r);
}else{
c_main(input,mask_null,r);
}
}
}
}
#define N 13
void init()
{
INT i=0;
short a[4]={0,1,2,3};
do{
o0[ i]=a[0];
o1[ i]=a[1];
o2[ i]=a[2];
o3[ i]=a[3];
i++;
}while(next_permutation(a,a+4));
for(i=0;i<24;i++){
short inv[4];
inv[o0[ i]]=0;
inv[o1[ i]]=1;
inv[o2[ i]]=2;
inv[o3[ i]]=3;
if(inv[2]<inv[3]){
mask_cd|=(1<<i);
}
if(inv[1]<inv[2]&&inv[2]<inv[3]){
mask_bcd|=(1<<i);
}
if(inv[0]<inv[1]&&inv[2]<inv[3]){
mask_ab_cd|=(1<<i);
}
}
}
int bits(int x){
int b=0,i;
for(i=0;i<32;i++)if(x&(1<<i))b++;
return b;
}
int main()
{
INT i=0,j,k,m;
init();
for(i=1;i<=N;i++)for(j=i;j<=N;j++)for(k=j;k<=N;k++)for(m=k;m<=N;m++){
c24(i,j,k,m,24);
}
}
mathe 2005-01-21
  • 打赏
  • 举报
回复
好像没有人感兴趣呀,把我的一个使用了上面结果的算24的程序给贴出来把,
给出任何四个数a,b,c,d以及一个和S,这个程序可以将所有用a,b,c,d算出S的不等价的表达式给找出来。

#include <stdio.h>
#include <map>
#include <algorithm>
using namespace std;
int pm[]={0x1,0x55,0x10515,0x555555,0x41041,0x15,0x30f3f,0xffffff,
0x3f,0x30f3f,0xaaff,0x20b,0xaaff,0x2cb2cb,0x1c71c7};
short table[]={
0, 65, 130, 195, 132, 261, 134, 199,
328, 201, 138, 203, 140, 205, 142, 207,
402, 467, 537, 410, 475, 412, 605, 414,
479, 354, 227, 164, 229, 166, 231, 42,
107, 172, 237, 174, 303, 691, 436, 501,
438, 503, 1416, 1481, 1738, 1803, 1420, 1485,
1871, 1432, 1497, 1754, 1819, 1436, 1501, 1887,
1760, 1825, 1442, 1507, 1893, 1446, 1511, 1776,
1841, 1458, 1523, 1909, 1462, 1527, 2883, 2503,
2899, 2519, 2921, 2541, 2937, 2557, 3331, 3975,
3915, 3535, 3287, 3931, 3551, 3937, 3557, 3369,
4013, 3953, 3573, 3325, 4301, 4573, 4327, 4599
};

short o0[24];
short o1[24];
short o2[24];
short o3[24];
char opprint[]={'+','-','*','/'};
int mask_cd,mask_bcd,mask_ab_cd;
#define mask_null 0xFFFFFF
#define mask_abcd 1

struct expression{
int value;
expression(int v):value(v){ }
int first_op()const{
return value & 3;
}
int second_op()const{
return (value >> 2)&3;
}
int third_op()const{
return (value >> 4)&3;
}
int graph_type()const{
return (value >> 6)/24;
}
int num_order()const{
return (value >> 6)%24;
}
};

typedef int INT;
struct factor_num{
INT up;
INT down;
factor_num(){}
factor_num(INT u,INT d):up(u),down(d){ }
};

typedef factor_num (*OperatorFun)(const factor_num& x,const factor_num& y);
factor_num sum(const factor_num& i,const factor_num& j){
INT d,u;
if(i.down==0||j.down==0){
d=0;
}else{
d=i.down * j.down;
u=i.up * j.down + j.up * i.down;
}
return factor_num(u,d);
}

factor_num dif(const factor_num& i,const factor_num& j){
INT d,u;
if(i.down==0||j.down==0){
d=0;
}else{
d=i.down * j.down;
u=i.up * j.down - j.up * i.down;
}
return factor_num(u,d);
}

factor_num prod(const factor_num& i,const factor_num& j){
INT d,u;
u=i.up * j.up;
d=i.down * j.down;
return factor_num(u,d);
}
factor_num ratio(const factor_num& i,const factor_num& j){
INT d,u;
if(i.down == 0 || j.down==0){
d=0;
}else{
d=i.down * j.up;
u=i.up * j.down;
}
return factor_num(u,d);
}
OperatorFun funs[]={sum,dif,prod,ratio};

bool equal_num(const factor_num& i,INT j)
{
if(i.down==0){
return false;
}else{
return i.up == j * i.down;
}
}

void show(INT input[],expression expr){
int order=expr.num_order();
INT aa=input[o0[order]];
INT bb=input[o1[order]];
INT cc=input[o2[order]];
INT dd=input[o3[order]];
short op1=expr.first_op();
char ops1=opprint[op1];
short op2=expr.second_op();
char ops2=opprint[op2];
short op3=expr.third_op();
char ops3=opprint[op3];
switch(expr.graph_type()){
case 0:
if(op1<2 && op2 >=2){
printf("(%d%c%d)%c",aa,ops1,bb,ops2);
} else {
printf("%d%c%d%c",aa,ops1,bb,ops2);
}
if(op2>=op3){
printf("(%d%c%d)",cc,ops3,dd);
}else{
printf("%d%c%d",cc,ops3,dd);
}
break;
case 1:
if(op2<2&&op3>=2)
printf("(");
if(op1<2&&op2>=2)
printf("(");
printf("%d%c%d",aa,ops1,bb);
if(op1<2&&op2>=2)
printf(")");
printf("%c%d",ops2,cc);
if(op2<2&&op3>=2)
printf(")");
printf("%c%d",ops3,dd);
break;
case 2:
if(op1<2&&op3>=2)
printf("(");
printf("%d%c",aa,ops1);
if(op1>=op2)
printf("(");
printf("%d%c%d",bb,ops2,cc);
if(op1>=op2)
printf(")");
if(op1<2&&op3>=2)
printf(")");
printf("%c%d",ops3,dd);
break;
case 3:
printf("%d%c",aa,ops1);
if(op1>=op3)
printf("(");
if(op2<2&&op3>=2)
printf("(");
printf("%d%c%d",bb,ops2,cc);
if(op2<2&&op3>=2)
printf(")");
printf("%c%d",ops3,dd);
if(op1>=op3)
printf(")");
break;
case 4:
printf("%d%c",aa,ops1);
if(op1>=op2)
printf("(");
printf("%d%c",bb,ops2);
if(op2>=op3)
printf("(");
printf("%d%c%d",cc,ops3,dd);
if(op2>=op3)
printf(")");
if(op1>=op2)
printf(")");
break;
}
}
xitianjile 2005-01-20
  • 打赏
  • 举报
回复
mark
zzwu 2005-01-13
  • 打赏
  • 举报
回复
上面错了,运算在树的节点上的分布 = 4^3 = 64, 所以总数 = 2*24*64 = 3072


zzwu 2005-01-13
  • 打赏
  • 举报
回复

x
/ \
y z
/ \ / \
a b c d

x
/ \
a Y
/ \
b Z
/ \
c d

1. 结合方式( 即树的个数) =2
2. 数的个数=|{ a,b,c,d}| =4, 数在每个树上的分布 = P( 4,4) =24
3. 运算节点数|{ x,y,z}| =3,运算种类|{ +,-,*,/ }| =4,运算在树的节点上的分布 = C( 4,3) =12

由此,总数 =2*24*12=576


mathe 2005-01-13
  • 打赏
  • 举报
回复
呵呵,我的要求是要对任意的a,b,c,d组合都相等的情况才算等价,
当然包含4个数字互不相等的情况。但是不是针对任何给定的4个数。
比如 6/9*(6*6)和 (9-6)*6+6都是等于24,但是这两个表达式我们认为不是等价的。
mathe 2005-01-13
  • 打赏
  • 举报
回复
To zzwu, 就是不考虑等价关系,你的结论还是不对。
比如表达式(a+b*c)/d的树形就不属于上面两种情况。
要注意/和-是不可以使用交换律的。
当然你可以看成总共有6种操作符。
mathe 2005-01-12
  • 打赏
  • 举报
回复
不对
rickone 2005-01-12
  • 打赏
  • 举报
回复
还有个前提,4个数字互不相等,如果相等情况会更少一些。
tarkey 2005-01-10
  • 打赏
  • 举报
回复
每种不同的二叉树都有64种不同的表达式(4 * 4 * 4)。
总共3种形状的二叉树,每种形状有3种不同的排列方法(ab, ac, ad在一边)。
最后结果是64 * 3 * 3,结果应该是576种不同的表达式。
mathe 2005-01-10
  • 打赏
  • 举报
回复
我计算出来的结果是互不等价的表达式是386种。
这个题目用于给大家作为挑战赛吧。
大家不一定需要完全编写代码,只要描绘出一些看来比较可行的方法,就可以了
mmmcd 2005-01-09
  • 打赏
  • 举报
回复
我想先构造出二叉树,然后改变其形态,根据节点运算符优先级判断改变是否等价
-
/ \
+ *
/ \ / \
a b c d

+
/ \
a -
/ \
b *
/ \
c d
baryjim 2005-01-08
  • 打赏
  • 举报
回复
a+b-c*d
外层有可以看成a+b-X,这样就有
(a+b)-X
a+(b-X)
分析到这一步就自己考虑吧!具体细节问题了
  • 打赏
  • 举报
回复
mark

33,010

社区成员

发帖
与我相关
我的任务
社区描述
数据结构与算法相关内容讨论专区
社区管理员
  • 数据结构与算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧