用这个好了,只不过输入的时候要按从小到大
好象有BUG,我暂时不太清楚
好象不行啊,我输入 1 2 3 8 结果是 0个算式 这些重复都是可行的算法,我想了很久,没有办法删除了,
比如
1*2*3*4
2*1*3*4
4*3*2*1
这些都是我们看来是一样的表达算式而已,对程序来说却是完全不同的计算次序,所以还真的难以在算法中高效率的取舍,看来只有在得到所有结果以后在进行一个比较来取舍了。那是比较简单的,不过又多加了步骤,时间也就花得更多。
不过如果游戏中不要求写出所有计算方法的话,那么可以在得到第一个算式的时候就停止
[此贴子已经被作者于2004-5-2 15:46:49编辑过]
问题挺多了,我要再好好修改一下
我本来想用波兰表示法进行算术计算的,给搞错了,哈哈
[此贴子已经被作者于2004-5-2 15:53:03编辑过]
以下是引用游侠无极限在2004-5-2 15:50:48的发言:
问题挺多了,我要再好好修改一下
我本来想用波兰表示法进行算术计算的,给搞错了,哈哈
还写啊?这么有空,建议帮我把vb的改成c的吧,优化优化,那真的可以写个小游戏了哦
[此贴子已经被作者于2004-5-2 15:55:47编辑过]
太晚了,现在决定用二叉树(第一次用)来做了,明天要出去,估计明天晚上能搞定 二叉树来组合字符串到是比较简便的,这样应该可以去掉很多重复
存在的问题:
加法和乘法交换律引起的重复
1*2*3*4
2*4*1*3
等的重复问题
原本输入的数存在重复导致的算式的重复
如:
3 3 8 8 得 24点的
8/(3-(8/3)) 重复
括号问题
[此贴子已经被作者于2004-5-3 23:06:15编辑过]
修正括号问题 下面的代码保存为.htm的文件就可以了
还是比较快的
<html>
<head>
<script language="vbs">
Function doop(op, con2, n(), s())
doop = True
Dim con
con = con2
Select Case op
Case 0
n(con) = n(con) + n(con + 1)
s(con) = "(" + s(con) + "+" + s(con + 1) + ")"
For con = con + 1 To UBound(n) - 1
n(con) = n(con + 1)
s(con) = s(con + 1)
Next
Case 1
n(con) = n(con) - n(con + 1)
s(con) = "(" + s(con) + "-" + s(con + 1) + ")"
For con = con + 1 To UBound(n) - 1
n(con) = n(con + 1)
s(con) = s(con + 1)
Next
Case 2
n(con) = n(con) * n(con + 1)
s(con) = "(" + s(con) + "*" + s(con + 1) + ")"
For con = con + 1 To UBound(n) - 1
n(con) = n(con + 1)
s(con) = s(con + 1)
Next
Case 3
doop = False
If n(con + 1) = 0 Then
Exit Function
ElseIf n(con) Mod n(con + 1) <> 0 Then
Exit Function
End If
doop = True
n(con) = n(con) / n(con + 1)
s(con) = "(" + s(con) + "/" + s(con + 1) + ")"
For con = con + 1 To UBound(n) - 1
n(con) = n(con + 1)
s(con) = s(con + 1)
Next
Case Else
doop = False
End Select
End Function
function startp()
Dim opn(3), opi(3), opj(2), opk(1)
Dim s(3), sj(2), sk(1), spp(3), sn(3)
Dim i, ii, j, jj, k, kk, p1, p2, p3, p0
'因为没有使用递归所以生命了较多的变量一保存穷据之前的状态
Randomize
For i = 0 To 3
opn(i) = 1 + Int(Rnd * 13)
sn(i) = CStr(opn(i))
Next
Text1.Value = cstr(opn(0)) + "" + cStr(opn(1)) + "" + cStr(opn(2)) + "" + cStr(opn(3))
List1.innertext = ""
Dim pp(3),mlen
mlen=0
For p0 = 0 To 3
pp(p0) = opn(0)
spp(p0) = sn(0)
For p1 = 0 To 2
If p1 = p0 Then p1 = p1 + 1
pp(p1) = opn(1)
spp(p1) = sn(1)
For p2 = 0 To 1
If p2 = p1 Or p2 = p0 Then p2 = p2 + 1
If p2 = p1 Or p2 = p0 Then p2 = p2 + 1
pp(p2) = opn(2)
spp(p2) = sn(2)
p3 = 0
If p3 = p1 Or p3 = p0 Or p3 = p2 Then p3 = p3 + 1
If p3 = p1 Or p3 = p0 Or p3 = p2 Then p3 = p3 + 1
If p3 = p1 Or p3 = p0 Or p3 = p2 Then p3 = p3 + 1
pp(p3) = opn(3)
spp(p3) = sn(3)
'以上三个for完成数字的不同排列顺序
'下面是更具不同的计算顺序琼据(按照前序计算的思路比较容易理解)
For i = 0 To 2
For ii = 0 To 3
'**********************
s(3) = spp(3)
opi(3) = pp(3)
For j = 0 To 2
opi(j) = pp(j)
s(j) = spp(j)
Next
'初始化数据(每次都必须恢复到穷据之前的状态)
'**********************
If doop(ii, i, opi, s) Then
'**********************
For j = 0 To 2
sj(j) = s(j)
Next
'sj(j)类似地跪调用是的队战(每次都必须恢复到穷据之前的状态)
'**********************
For j = 0 To 1
For jj = 0 To 3
'**********************
For k = 0 To 2
opj(k) = opi(k)
s(k) = sj(k)
Next
'初始化数据(每次都必须恢复到穷据之前的状态)
'**********************
If doop(jj, j, opj, s) Then
'**********************
For k = 0 To 1
sk(k) = s(k)
Next
'...
'**********************
For kk = 0 To 4
'**********************
For k = 0 To 1
opk(k) = opj(k)
s(k) = sk(k)
Next
'...
'**********************
If doop(kk, 0, opk, s) And opk(0) = 24 Then
if len(s(0)) > mlen then mlen=len(s(0))
list1.cols=mlen
If instr(List1.innertext,s(0))=0 Then List1.innertext = List1.innertext + s(0)+chr(13)
End If
Next
End If
Next
Next
End If
Next
Next
Next
Next
Next
End function
</script>
</head>
<body>
<p id="pp">
<input type="button" style="width:150" id="button1" value="测试" onclick="startp()"></input><br>
<input style="width:150" id="text1"></input><br>
<textarea cols="15" style="height:300" id="list1"></textarea><br>
</p>
</body>
</html> 没有取出重复的方法真实不好意思 晕,好多For ... Next,这样就是不太通用
要除去重复的,实在困难,我想是不是可以给一个算式一个特征码,以判别是否重复,可以这个特征码不好找啊 现在是vb可,我准备修改原来的代码 以下是引用唐明在2004-5-8 8:01:19的发言:
现在是vb可,我准备修改原来的代码
但是你里面还有错误啊
比如
5 5 11 7 你的程序竟然得不到算式啊,而我用我的那个跑了一下得到如下
5*(7-11/5) = 24
5*(7-(11/5)) = 24
5*(7-11/5) = 24
5*(7-(11/5)) = 24
For 好多,注释太少了,变量干什么的我都看不出来,所以你的程序那里出问题我也看不出来,那么多for差点看傻了,还不如低归舒服多了。 加油加油
[此贴子已经被作者于2004-5-8 9:50:08编辑过]
烦
[此贴子已经被作者于2004-5-8 18:29:04编辑过]
这些是原始的版本代码没什么测试
这次5,5,11,7还是个问题 以下是引用唐明在2004-5-8 10:47:10的发言:
这些是原始的版本代码没什么测试
这次5,5,11,7还是个问题
我也是随便测试了一个,就碰上了
应该还有很多类似情况了
请问如何实现4个数字的 所有排列方式
5,5,11,7的问题就在这里
向5,5,7,11就有结果了5*(7-11/5)
[此贴子已经被作者于2004-5-8 18:33:46编辑过]
如果是只有4个数字,那么一共也才4!=4*3*2*1=24种,那么你全部列出来就可以了啊。24钟不算多。
几天前的东西,现在没有大兴趣了
过重复代码过多,比如二叉树的建立等等#include <stdio.h>
#include <stdlib.h>
typedef struct node
{
float Data;
char Formula;
int frist; //优先级
struct node *Lchild;
struct node *Rchild;
} BinTree;
void CreatBinTree(BinTree *Tree,int *nArray);
void FreeBinTree(BinTree *Tree);
void AfterBinTree(BinTree *Tree,void func(BinTree*));
float CalcBinTree(BinTree *Tree);
float GetFormulaVal(int *Formula,int count);
void ShowFormula(int *Formula,int count);
void AfterNode(BinTree *Tree);
void GetFormula(BinTree *Tree);
void Myitoa(BinTree *Tree);
int EnumFormula(int *FormulaNum,int num,int sum);
void Restore(int *Formula,int *NumSym,int *temp,int count);
int IsOK(int *Formula,int count);
int FindInt(int *nArray,int n,int len);
int UpZero(int *nArray,int n);
int IsDownNumSame(int *temp,int count,int num);
const char cSym = {"","+","-","*","/"};
int main(int argc, char *argv[])
{
int i,n,*Array;
//printf("几个数?");
//scanf("%d",&n);
n =4;
Array = (int*)calloc(n,sizeof(int));
printf("请输入%d个数(用回车或者空格分开):",n);
for(i=0;i<n;i++)
scanf("%d",&Array);
printf("总计%d个式子\n",EnumFormula(Array,n,24));
free(Array);
system("PAUSE");
return 0;
}
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; //载入进行穷举的运算符号
for(i=0;i<num*2;i++) temp = 0;
// 穷举开始,结束的标志为波兰表达式代号空间最后一位已进位,即前面各位已穷举完成
while(temp == 0)
{
if(!IsDownNumSame(temp,num*2-1,num))
{
Restore(Formula,NumSym,temp,num*2-1); //还原波兰表达式
if(IsOK(Formula,num*2-1))
{
float t; //结果偏差
t= GetFormulaVal(Formula,num*2-1) -sum;
if(t>-0.01 && t <0.01) //结果为浮点数,只能进行近似比较
{
result++;
ShowFormula(Formula,num*2-1);
}
}
}
temp++; //穷举动力
for(i=0;temp > num+3 && i<num*2-1;i++) //代码空间类进位
{
temp =0;
temp++;
}
}
// 释放内存
free(temp);
//free(Formula); //??此处不知为什么会出现错误
free(NumSym);
return result;
}
// 由代码表还原为波兰表达式
void Restore(int *Formula,int *NumSym,int *temp,int count)
{
int i;
for(i=0;i<count;i++) Formula = NumSym];
}
// 判断是否符合波兰表达式
// 符合的条件是每个运算符号前必须是操作数个数多了运算符个数
// 且运算符个数为总数减一的一半
int IsOK(int *Formula,int count)
{
int i,j;
for(i=0,j=1;i<count;i++)
if(Formula<0)
if(UpZero(Formula,i)>j) j++;
else break;
if(i<count || j != (int)count/2+1) return 0;
else return 1;
}
// 查找数组大于0的个数
int UpZero(int *nArray,int n)
{
int i,result=0;
for(i=0;i<n;i++) if(nArray>=0) result++;
return result;
}
// 查找数组中,小于Num的数是否有重复
int IsDownNumSame(int *temp,int count,int num)
{
int i;
for(i=0;i<count;i++)
{
if(temp < num)
if(FindInt(temp,temp,i) != 0) return 1;
}
return 0;
}
// 查找数所在数组的位置,返回0为未找到
int FindInt(int *nArray,int n,int len)
{
int i;
for(i=0;nArray != n && i<len;i++);
if(i>=len) i=0;
else i++;
return i;
}
// 计算算式结果
float GetFormulaVal(int *Formula,int count)
{
float result;
BinTree *head = (BinTree*)malloc(sizeof(BinTree)); //二叉树头节点
int *nArray = (int*)calloc(count+1,sizeof(int)); //波兰表达式储存数组,首位表示数组有效长度
int i;
for(i=1;i<=count;i++) nArray = Formula; //复制波兰表达式
nArray = count;
CreatBinTree(head,nArray); //建立二叉树
result = CalcBinTree(head); //计算二叉树算式
AfterBinTree(head,&FreeBinTree); //释放二叉树空间
free(nArray);
return result;
}
float CalcBinTree(BinTree *Tree)
{
AfterBinTree(Tree,&AfterNode);
return Tree->Data;
}
// 后序遍历二叉树进行计算,但会破坏二叉树本身
// 一个结点的结果为左子树 (运算符) 右子树
void AfterNode(BinTree *Tree)
{
switch((int)Tree->Data)
{
case -1:
Tree->Data = Tree->Lchild->Data + Tree->Rchild->Data;
break;
case -2:
Tree->Data = Tree->Lchild->Data - Tree->Rchild->Data;
break;
case -3:
Tree->Data = Tree->Lchild->Data * Tree->Rchild->Data;
break;
case -4:
Tree->Data = Tree->Lchild->Data / Tree->Rchild->Data;
break;
}
}
// 打印算式
void ShowFormula(int *Formula,int count)
{
BinTree *head = (BinTree*)malloc(sizeof(BinTree)); //二叉树头节点
int *nArray = (int*)calloc(count+1,sizeof(int)); //波兰表达式储存数组,首位表示数组有效长度
int i;
for(i=1;i<=count;i++) nArray = Formula; //复制波兰表达式
nArray = count;
CreatBinTree(head,nArray);
AfterBinTree(head,&Myitoa); //初始化二叉树字符窜部分
AfterBinTree(head,&GetFormula); //转化为普通表达式
printf("%s\n",head->Formula);
AfterBinTree(head,&FreeBinTree); //释放二叉树空间
free(nArray);
}
// 类似计算二叉树
// 会破坏二叉树本身
void GetFormula(BinTree *Tree)
{
// printf(Tree->Formula);
if(Tree->Data <0)
{
char temp;
if(Tree->Lchild->frist < Tree->frist)
{
strcpy(temp,Tree->Lchild->Formula);
strcpy(Tree->Lchild->Formula,"(");
strcat(Tree->Lchild->Formula,temp);
strcat(Tree->Lchild->Formula,")");
}
if(Tree->Rchild->frist < Tree->frist
|| (int)Tree->Data == -2 && Tree->Rchild->frist == 0
|| (int)Tree->Data == -4 && Tree->Rchild->frist != 2)
{
strcpy(temp,Tree->Rchild->Formula);
strcpy(Tree->Rchild->Formula,"(");
strcat(Tree->Rchild->Formula,temp);
strcat(Tree->Rchild->Formula,")");
}
strcpy(temp,Tree->Formula);
strcpy(Tree->Formula,Tree->Lchild->Formula);
strcat(Tree->Formula,cSym[-(int)Tree->Data]);
strcat(Tree->Formula,Tree->Rchild->Formula);
}
}
// 对二叉树字符串部分赋值
void Myitoa(BinTree *Tree)
{
if(Tree->Data>=0)
{
itoa((int)Tree->Data,Tree->Formula,10);
Tree->frist = 2;
}
else
{
Tree->frist=Tree->Data < -2 ? 1:0;
strcpy(Tree->Formula, cSym[-(int)Tree->Data]);
//Tree->Formula = 0;
}
}
//从一个波兰表达式建立一个二叉树链表,需指定一个头节点
void CreatBinTree(BinTree *Tree,int *nArray)
{
Tree->Data = nArray--];
if(Tree->Data < 0)
{
Tree->Rchild = (BinTree*)malloc(sizeof(BinTree));
CreatBinTree(Tree->Rchild,nArray);
Tree->Lchild = (BinTree*)malloc(sizeof(BinTree));
CreatBinTree(Tree->Lchild,nArray);
}
else
{
Tree->Lchild = 0;
Tree->Rchild = 0;
}
}
// 释放二叉树空间
void FreeBinTree(BinTree *Tree)
{
free(Tree);
}
// 后序遍历二叉树
// 方便其他函数调用,func为要对各个结点进行操作的函数指针
void AfterBinTree(BinTree *Tree,void func(BinTree*))
{
if(Tree)
{
AfterBinTree(Tree->Lchild,func);
AfterBinTree(Tree->Rchild,func);
func(Tree);
}
}