hzzh
发表于 2004-5-8 17:31:00
这个题目不容易呢,好多高手都出马了,不错不错,不佩服的不行。
来了点好奇心,对游侠无极限 的程序运行了一下
算法还没有看懂,为什么结果会都是重复的?
“
请输入4个数(用回车或者空格分开):5 5 8 8
5*5-8/8
5*5-8/8
5*5-8/8
5*5-8/8
总计4个式子
“
另外程序有一点点小错误:
”
int EnumFormula(int *FormulaNum,int num,int sum)
{
int result = 0;
int *NumSym = (int*)calloc(num+4,sizeof(int)); //操作数运算符组成的可枚举组
int *Formula = (int*)calloc(num*2-1,sizeof(int)); //波兰表达式储存空间
int *temp = (int*)calloc(num*2,sizeof(int)); //波兰表达式的代号表示空间
int i,j;
for(i=0;i<num;i++) NumSym = FormulaNum; //载入进行穷举的操作数
for(j=0;j<5;j++) NumSym = -j-1; //载入进行穷举的运算符号
“
前面定义: int *NumSym = (int*)calloc(num+4,sizeof(int)); //操作数运算符组成的可枚举组
后来二句:
for(i=0;i<num;i++) NumSym = FormulaNum; //载入进行穷举的操作数
for(j=0;j<5;j++) NumSym = -j-1; //载入进行穷举的运算符号
当num=4时,经过第一个for,i=4,第二个for中 NumSym, i+j=8,NumSym越界了
唐明
发表于 2004-5-8 18:11:00
‘最后一次发代码
<html>
<head>
<script language="VBScript" type="text/VBScript">
dim o(3)''4个操作数
dim s(3)''操作数串
dim p(3)''当前运算之前的运算
dim oo(3,1)''当前运算之前的运算的前后两个操作书
function try(n)
dim opp(3)
dim spp(3)
dim ppp(3)
dim oopp(3,1)''用来保存相应的原始数据
for i=0 to n
opp(i)=o(i)
spp(i)=s(i)
ppp(i)=p(i)
oopp(i,0)=oo(i,0)
oopp(i,1)=oo(i,1)
next
for i=1 to n
for ii=0 to 4
if ii=2 then ii=ii+1
for iii=0 to n
o(iii)=opp(iii)
s(iii)=spp(iii)
p(iii)=ppp(iii)
oo(iii,0)=oopp(iii,0)
oo(iii,1)=oopp(iii,1)''尝试之前先还原
next
if doop(ii,i-1) then
if n=1 then
if (abs(24-o(0))<0.0001) and (instr(list1.innertext,s(0))=0) then
s(0)=left(s(0)+space(10),17)
list1.innertext=list1.innertext+s(0)
end if
else
try(n-1)'类似地跪
end if
end if
next
next
end function
function doop(op,con)
' ↑进行的运算
' ↑这次运算的位置
'p(con) 之前的运算
'p(con+1) 之后的运算
'oo(con,0) 之前的运算的前操作书
'oo(con,1) 之前的运算的后操作书
'oo(con+1,0) 之后的运算的前操作书
'oo(con+1,1) 之后的运算的后操作书
'o(con) 现在将要进行的运算的前操作数
'o(con+1) 现在将要进行的运算的后操作数
's(con) 现在将要进行的运算的前操作数串
's(con+1) 现在将要进行的运算的后操作数串
'下面的例子前面部分数不允许的
'12/12*12+12=12+12/12*12
'(2+1)*(6+2)=(6+2)*(2+1)
'(6+2)*(3/1)=(6+2)*3*1=3*1*(6+2)
'6*4/4*4=6/4*4*4
'6*4+4-4=6*4-4+4
'4*(4+4)-8=(4+4)*4-8
'12*3/2+6=12/2*3+6
'.............等等差不多的狮子都认为是相同的
'结果的重复数量不是很多,但也可能漏掉了不少,要多多修改才行
'12/12*(13+11)<>(13+11)/12*12
'应为前面一个是1*24,后面是24*12/12,计算的顺序不同数值不同,但是12*(13+11)/12=12/12*(13+11)<>(13+11)*12/12'最后那个是不允许的(p(con)=op-1)就是乘法之后有计算过的除法
'...........
'代码设定的运算级别
' "+"0
' "-"1
' "*"3
' "/"4
'"无运算"6
doop=true
''************************
''这是为了避免一个奇怪的bug
''这次避免了2,2,2,3问题
i=len(s(0))
iii=0
for i=i to 1 step -1
ii= mid(s(0),1)
if ii>="0" and ii<="0" then iii=iii+1
next
if iii=len(sp(0)+sp(1)+sp(2)+sp(3)) then
doop=false
exit function
end if
''************************
if (p(con)=op-1) or (abs(p(con+1)-op)<2) or ((p(con)=op) and (oo(con,1)<o(con+1))) then
'把恩代码中下列情况是不允许的
'"+"/"-"之厚有机酸过的"+"/"-"
'"*"/"/"之厚有机酸过的"*"/"/"比如 5*(2*9)是非法的
'就是abs(p(con+1)-op)<2
'"-"之前有计算过的"+"
'"/"之前有计算过的"*"
'就是(p(con)=op-1)
'"+"/"-"/"*"/"/"之前是与它相同的运算,而之前的运算的后操作数<现在将要进行的运算的后操作数
'就是(p(con)=op) and (oo(con,1)<o(con+1))
doop=false
exit function
end if
'"+"/"-"/"/"的前操作数<后操作数
'"-"/"*"/"/"的前操作数=0
'"*"/"/"后操作数=0
'"/"后操作数=1
'"+"之前运算前操作书<之后运算前操作书
'"+"之前运算前操作书=之后运算前操作书且'"+"之前运算后操作书<之后运算后操作书
'"*"的前操作数<后操作数且之前和将要进行运算的级别之差>1
'"+"/"*"之前运算级别<之后运算级别且之后运算级别<>6
'if ((oo(con,0)<oo(con+1,0)) or ((oo(con,0)=oo(con+1,0)) and (oo(con,1)<oo(con+1,1)))) and (abs(p(con)-p(con+1))<2) then
'这句子描述比较麻烦
'"/"
select case op
case 0
if (o(con)<o(con+1)) or (p(con)<p(con+1) and p(con+1)<>6) or (p(con)>p(con+1) and p(con)=6) or (oo(con,0)<oo(con+1,0) or ((oo(con,0)=oo(con+1,0)) and (oo(con,1)<oo(con+1,1)))) then
doop=false
exit function
end if
if p(con) > 2 then oo(con,0)=o(con)'更新前操作数
'计算
o(con)=o(con)+o(con+1)
s(con)=s(con)+"+"+s(con+1)
case 1
if (o(con)<o(con+1)) or o(con)=0 then
doop=false
exit function
end if
if p(con) > 2 then oo(con,0)=o(con)'更新前操作数
'计算
o(con)=o(con)-o(con+1)
s(con)=s(con)+"-"+s(con+1)
case 3
''if (o(con)<o(con+1)) and (abs(p(con)-p(con+1))<2 ) then
''*************************************↓修改
if (o(con)<o(con+1)) and (abs(p(con)-op)>1)then
doop=false
exit function
end if
if (o(con)=0) or (o(con+1)=0) or ((p(con)<p(con+1)) and (p(con+1)<>6)) then
doop=false
exit function
end if
if ((oo(con,0)<oo(con+1,0)) or ((oo(con,0)=oo(con+1,0)) and (oo(con,1)<oo(con+1,1)))) and abs(p(con)-p(con+1))<2 then
doop=false
exit function
end if
if p(con) < 2 then'更新前操作数和括号
oo(con,0)=o(con)
s(con)="("+s(con)+")"
end if
if p(con+1) < 2 then s(con+1)="("+s(con+1)+")"'括号
'计算
o(con)=o(con)*o(con+1)
s(con)=s(con)+"*"+s(con+1)
case 4
if (o(con)<o(con+1)) or (o(con)=0) or (o(con+1)<2) then
doop=false
exit function
end if
if p(con) < 2 then'更新前操作数和括号
oo(con,0)=o(con)
s(con)="("+s(con)+")"
end if
if p(con+1) < 2 then s(con+1)="("+s(con+1)+")"'括号
'计算
o(con)=o(con)/o(con+1)
s(con)=s(con)+"/"+s(con+1)
case else
doop=false
exit function
end select
oo(con,1)=o(con+1)'更新后操作数
p(con)=op'更新运算
'每次运算会减少操作数,后面数据向前移动1位
for i=con+1 to 2
o(i)=o(i+1)
s(i)=s(i+1)
p(i)=p(i+1)
oo(i,0)=oo(i+1,0)
oo(i,1)=oo(i+1,1)
next
end function
dim oip(3)
dim sp(3)
dim pp(3)
dim oop(3,1)
function init()
dim mle
list1.innertext=""
for i=0 to 3
if textx(i).value="" then exit function
oip(i)=textx(i).value-0
sp(i)=cstr(oip(i))
pp(i)=6
oop(i,0)=oip(i)
oop(i,1)=oip(i)
next
''修正过的排列组合穷据
dim freeo(3),f(3)
For p0 = 0 To 3
f(0)=p0
For p1 = 0 To 2
foo=0
for i=0 to 3
if i<>p0 then
freeo(foo)=i
foo=foo+1
end if
next
f(1)=freeo(p1)
For p2 = 0 To 1
foo=0
for i=0 to 3
if i<>p0 and i<>f(1) then
freeo(foo)=i
foo=foo+1
end if
next
f(2)=freeo(p2)
p3 = 0
foo=0
for i=0 to 3
if i<>p0 and i<>f(1) and i<>f(2) then
freeo(foo)=i
foo=foo+1
end if
next
f(3)=freeo(p3)
for i=0 to 3
o(i)=oip(f(i))
s(i)=sp(f(i))
p(i)=pp(f(i))
oo(i,0)=oop(f(i),0)
oo(i,1)=oop(f(i),1)
next
if instr(mle,s(0)+s(1)+s(2)+s(3)+";") =0 then
mle=mel+s(0)+s(1)+s(2)+s(3)+";"
try(3)
end if
next
next
next
if list1.innertext="" then list1.innertext="无解"
end function
</script>
</head>
<body>
<p>
<input type="button" id="testme" value="Try" onClick="init">
</p>
<p>
<input type="text" id="textx" style="width:30">
<input type="text" id="textx" style="width:30">
<input type="text" id="textx" style="width:30">
<input type="text" id="textx" style="width:30">
</p>
<p>
<textarea id="list1" cols="17" style="height:300" rows="1"></textarea>
</p>
</body>
</html>
[此贴子已经被作者于2004-5-8 18:20:59编辑过]
yzhlinux
发表于 2004-5-8 18:42:00
佩服佩服,不佩服不行了,
代码越来越工整,注释越来越详细实用,
真是长江后浪推前浪啊,前浪死在沙滩上
游侠无极限
发表于 2004-5-8 21:11:00
以下是引用hzzh在2004-5-8 17:31:09的发言:
这个题目不容易呢,好多高手都出马了,不错不错,不佩服的不行。
来了点好奇心,对游侠无极限 的程序运行了一下
算法还没有看懂,为什么结果会都是重复的?
“
请输入4个数(用回车或者空格分开):5 5 8 8
5*5-8/8
5*5-8/8
5*5-8/8
5*5-8/8
总计4个式子
“
另外程序有一点点小错误:
”
int EnumFormula(int *FormulaNum,int num,int sum)
{
int result = 0;
int *NumSym = (int*)calloc(num+4,sizeof(int)); //操作数运算符组成的可枚举组
int *Formula = (int*)calloc(num*2-1,sizeof(int)); //波兰表达式储存空间
int *temp = (int*)calloc(num*2,sizeof(int)); //波兰表达式的代号表示空间
int i,j;
for(i=0;i<num;i++) NumSym = FormulaNum; //载入进行穷举的操作数
for(j=0;j<5;j++) NumSym = -j-1; //载入进行穷举的运算符号
“
前面定义: int *NumSym = (int*)calloc(num+4,sizeof(int)); //操作数运算符组成的可枚举组
后来二句:
for(i=0;i<num;i++) NumSym = FormulaNum; //载入进行穷举的操作数
for(j=0;j<5;j++) NumSym = -j-1; //载入进行穷举的运算符号
当num=4时,经过第一个for,i=4,第二个for中 NumSym, i+j=8,NumSym越界了
真是太感谢了,想必释放错误是由于这个越界啊
至于重复,其实是这样的:
你输入的 5 5 8 8,在穷举中,第一个5和第二个5不等价,同样第三个8和第四个8不等价,所以结果是
5(1)*5(2)-8(3)/8(4)
5(2)*5(1)-8(3)/8(4)
5(1)*5(2)-8(4)/8(3)
5(2)*5(1)-8(4)/8(3)
唐明
发表于 2004-5-9 12:21:00
给游侠无极限
定义
操作数:v1,v2,v3,v4 就是4个数字
运算次序:px,p1,p2,p3,px计算的顺序,比如9*9*9*9是6,1,2,3,6 || 5*(8+9)/3是6,3,1,2,6等等
运算:ox,o1,o2,o3,ox进行的计算
操作数串:s1,s2,s3,s4
特征马:v1-o1-v2-v12-o2-v3-v123-o3-v4这是按照p1,p2,p3的次序且v1>v2,v12>v3,v123>v4
次序px=6
运算ox="="
1)次序为 : "()" > "/" > "*" > "-" > "+"
相应级别: 5 4 3 1 0
2)检查前面 / 后面的运算,如果与现在将要进行的相同则继续检查前"面"生成的特征马的"后"面一个操作数/"后"面生成的特征马的"前"面一个操作数,"前"面生成的特征马的"后"面一个操作数>现在的"后"操作数 / "后"面生成的特征马的"前"面一个操作数>现在的"前"操作数,则跳出运算 (5月13日注:这规则是在前后都有计算过的运算时)
3)"+"/"*"作运算时"前"面的运算级别与现在将要进行的"相"同则"前"面的运算的"后"操作数必须是>=现在将要进行运算的"后"操作数,如果不符合则跳出运算
4.1)"/" / "*"检查前/后面的运算,小雨当前运算级别超过1,则在相应操作数串上+()
4.2)"/"检查"后"面的运算级别<=4,则在相应操作数串上+() 如果认为/(a/b)=/b*a/(a*b)=/a/b 则"后"面的运算级别=4或=3跳出运算
4.3)"*"检查"后"面的运算级别<3或=4,则在相应操作数串上+()
4.4)"-"检查"后"面的运算级别<=1,则在相应操作数串上+() 如果认为-(a-b)=-b+a-(a+b)=-b-a 则"后"面的运算级别=1或=0跳出运算
5)第2,3次运算结束时这次运算的运算代替次序在他之前的运算的运算
6)王成一个表达时的计算时应当分别保存特征马和最总的操作数串(完整的表达式串)在一个容器之中,已经存在相同的特征马则应该放弃现在的特征马和最总的操作数串(完整的表达式串)
7)如果认为*1和/1是相同的则两者只能选一,(禁止(当...时跳出运算)*/1或/1中的一个)或(*/1或/1中的一个生成特征妈时转换为对方)
8.1)为了避免6+3+2和6+(3+2)6+3-2和6+(3-2)...重复,"+"后面有"+"/"-"跳出运算
8.2)为了避免6*3*2和6*(3*2)6*3/2和6*(3/2)...重复,"*"后面有"*" / "/"跳出运算
一个特征马的存储形式:char={{v1,o1,v2,o2,v3,o3,v4},...}
这里所有跳出运算都可以通过改变前后的特征马而不跳出运算,但是那样很麻烦
这个产生特真马的前提就是我的代码(规则是比较乱的)的前提,这里只是描述的相对清楚,特征马就是我的代码中允许的表达时的计算过程,所以我的这个铁自可能是多余的
****************************************
例子1:
次序左右的6
运算左右的=
省略了
****************************************
操作数:v1,v2,v3,v4
运算次序: p1,p2,p3
运算: o1,o2,o3
操作数串:v1,v2,v3,v4
下面是计算
原操作数: v1,v2,v3,v4
一次运算: v12 ,v3,v4
运算次序: px,p2,p3
运算: ox,o2,o3
操作数串: v1p1v2,v3,v4,v4
二次运算: v123,v4
运算次序: px,px,p3
运算: ox,ox,o3
操作数串: v1p1v2p2v3,v4,v4,v4
三次运算: v1234
运算次序: px,px,px
运算: ox,ox,ox
操作数串: v1p1v2p2v3p3v4,v4,v4,v4
下面是特征马
v1-o1-v2-v12-o2-v3-v123-o3-v4
这是按照p1,p2,p3的次序且v1>v2,v12>v3,v123>v4
最总的操作数串(完整的表达式串)
v1p1v2p2v3p3v4
****************************************
****************************************
例子1的实例:
次序左右的6
运算左右的=
省略了
****************************************
操作数:2 ,2 ,3 ,2
运算次序: 1 ,2 ,3
运算: + ,* ,*
操作数串:2 ,2 ,2 ,2
就是: (2+2)*3*2
下面是计算
原操作数:2 ,2 ,3 ,2
一次运算: 4 ,3 ,2
运算次序: 6 ,2 ,3
运算: + ,* ,* 生成2-+-2
操作数串:2+2,3,2,2
二次运算: 12,2
运算次序: 6 ,6 ,3
运算: * ,* ,* 生成4-*-3
操作数串:(2+2)*3,2,22 加上括号
三次运算: 24
运算次序: 6 ,6 ,6
运算: * ,* ,* 生成12-*-2
操作数串:(2+2)*3*2,2,2,2
下面是特征马
2-+-2-4-*-3-12-*-2
按照1,2,3(就是次序)的顺序
最总的操作数串(完整的表达式串)
(2+2)*3*2
****************************************
再比如2*(2+2)*3
特征马
2-+-2-?-?-?-?-?-?
后面跳出了计算,这个特征马/最总的操作数串(完整的表达式串)应当放弃
和(2+2)*3*2不会重复
再比如6,6,6,6
可以生成的特征马
6-+-6-12-+-6-18-+-6
6-*-6-36---6-30---6
再比如12,12,12,12
可以生成的特征马
12-+-12-24-/-12-2-*-12
12-/-12-1-*-12-12-+-12
12-+-12-12-/-12-1-*-24
[此贴子已经被作者于2004-5-12 19:06:09编辑过]
游侠无极限
发表于 2004-5-11 12:15:00
不太明白,比如
1*2*3*4
2*4*3*1
2*1*3*4
2/(1/(3*4))
的特征码是多少呢
唐明
发表于 2004-5-12 19:03:00
2)检查前面 / 后面的运算,如果与现在将要进行的相同则继续检查前"面"生成的特征马的"后"面一个操作数/"后"面生成的特征马的"前"面一个操作数,"前"面生成的特征马的"后"面一个操作数>现在的"后"操作数 / "后"面生成的特征马的"前"面一个操作数>现在的"前"操作数,则跳出运算 (5月13日注:这规则是在前后都有计算过的运算时)
↓修改 ↓ (5.13.2004修改)
3)"+"/"*"作运算时"前"面的运算级别与现在将要进行的"相"同则"前"面的运算的"后"操作数必须是>=现在将要进行运算的"后"操作数,如果不符合则跳出运算
4.2)"/"检查"后"面的运算级别<=4,则在相应操作数串上+() 如果认为/(a/b)=/b*a/(a*b)=/a/b 则"后"面的运算级别=4或=3跳出运算 (我认为是相等的)
8.2)为了避免6*3*2和6*(3*2)6*3/2和6*(3/2)...重复,"*"后面有"*" / "/"跳出运算
更见规则,你给出的狮子只有4*3*2*1是合法的,其他狮子舞发生成特征马
4*3*2*1
次序:1,2, 3
运算*(3) ,*(3),*(3)括号内是级别
4*3=12 -> 4-3-3 结果12
12*2=24-> 12-*-2结果24
24*1=24-> 24*1 结果24
↓ ↓ ↓都是级别
最总特征马4-3-3-12-3-2-24-3-1
4*3 12*2 42*1
其他可以得到的特征吗(还有其他我原来里出的规则)
4-0-2-3-0-1-6-3-4 (4+2)*(3+1)
3-0-2-5-0-1-6-3-4 (3+2+1)*4
游侠无极限
发表于 2004-5-13 20:41:00
我想了一个特征码:
取每个操作数所进行的运算符
即:
1*2*3*4
各个操作数进行的运算分别为:
1 *
2 *
3 *
4 *
特征码为****
(1+3)*(2+4)为
1+
3+
2+
4+
为++++
2/(1/(3*4))
2/
1/
3*
4*
为**//
隐含特征码为四个操作数和运算结果,因为相同,所以除去
目的是消除因加法和乘法交换率引起的重复
不知道有没有漏掉的,或者误除的
[此贴子已经被作者于2004-5-13 20:43:35编辑过]