C++枚举算法运算符填充实现

       最近在一本算法设计书上看到一个用枚举法填入运算符(或者是括号),使之运算结果满足一定条件。例如在5 5 5 5 5 这5个数之间插入+ - * / 或者是括号运算符,使之最后结果等于5。在这个过程中有几个需要注意的问题:

        1、运算符优先级问题:括号>乘除>加减;

        2、数据存储问题:运算数据,运算符,括号。并且这三种数据存在所能在的位置数量存在关系:n(括号)=n(运算数据)+1,n(运算数据)=n(运算符)+1。

        3、括号加入问题:加入括号的目的是改变运算顺序,但有时加入括号并不改变运算顺序。例如 5+5+5+5+5 与 (5+5+5)+5+5 完全一样,没有任何区别。

        针对以上情况,我的解决方案是:

        1、按照优先级的不同分三步得到结果;

        2、运算数据用 digit[]存储,运算符用 method[] 存储,括号用结构体表示:

        

struct parenthesis
{
	int left;
	int right;
};


其中left表示左括号位置,right表示右括号位置。

        3、引入 bool check() 函数进行判断。如果返回true 则说明计算括号加入有误,进行下一步。通过分析发现:要使括号加入有意义,至少需要满足两种情况的一种:1、括号内部运算符不统一,即有第一级第二级运算的混合。2、括号内部全为加减,并且挨着括号外部的左右两个运算符至少有一个为第一级运算符,即乘除:

inline bool check(parenthesis par,int method[])
{
	int i=0;
	for( i=par.left;i<par.right-1;i++)
	{
		if(method[i]>=3)
			continue;
		else
			break;
	}
	if(i==par.right-1)
		return true;
	for(i=par.left;i<par.right-1;i++)
	{
		if(3-method[i]>0)
			continue;
	}
	if(i==par.right-1)
	{
		if(par.left>=1&&par.right<=digitnum-1)
		{
			if(method[par.left-1]<3&&method[par.right-1]<3)
				return true;
			else 
				return false;
		}
		if((par.left==0&&method[par.right-1]<3&&par.right<digitnum)||(par.right==digitnum&&method[par.left-1]<3))
			return true;
		else
			return false;
	}
}


    此外,转为计算乘除引入函数:

double begincal(int* p_slow,int* p_fast,int b,double digit[],int method[])
{
	int begin=b,end=b+(p_fast-p_slow);
	double results;
	if(*p_slow<3)
		results=digit[begin+1];
	else
		results=digit[begin];
	for(int i=method[begin]>=3?begin:(begin+1);i<=end;i++)
	{
		if(method[i]==3)
			results*=digit[i+1];
		if(method[i]==4)
			results/=digit[i+1];
	}
	return results;
}

     整体计算引入函数:

double calculate(double digit[],int method[], int n)//calculate the whole equation;
{
	int* p_slow=method;
	int* p_fast=method;
	double results=0;
	vector<double> vec;
	vector<int> met;
	for(int m=0;m<n;m++)
	{
		if(method[m]<3)
			met.push_back(method[m]);
	}
	if(met.size()==0)
	{
		results=digit[0];
		for(int i=0;i<n;i++)
		{
			if(method[i]==3)
				results*=digit[i+1];
			if(method[i]==4)
				results/=digit[i+1];
		}
		return results;
	}
	int i=0;
	while (i<n)
	{
		if(method[i]<3&&i==0)//决定第一个数是否堆入vec;
			vec.push_back(digit[i]);
		if((method[i]>=3&&(i+1)<n/*&&method[i+1]>=3*/)||(method[i]<3&&(i+1)<n&&method[i+1]>=3))
		{
			int b=i,j=i;
			p_slow=&method[i];
			p_fast=&method[i];
			while((++j)<n&&method[j]>=3)
				p_fast++;
			results=begincal(p_slow,p_fast,b,digit,method);
			vec.push_back(results);
			if(j<n)
				i=j;
			else
				break;
		}
		if(method[i]<3&&(i+1)<n&&method[i+1]<3)//决定中间数是否堆入;
		{
			vec.push_back(digit[i+1]);
			i++;
		}
		if(method[i]<3&&i==(n-1))//决定末尾数是否堆入;
		{
			vec.push_back(digit[i+1]);
			i++;
		}
	}
	results=vec[0];
	for(int k=0;k<met.size();k++)
	{
		if(met[k]==1)
			results+=vec[k+1];
		if(met[k]==2)
			results-=vec[k+1];
	}
	return results;
}

       为了方便显示,引入一个显示函数和一个转换函数:

char num2char(int i)//transfer the num to char;
{
	if(i==1)
		return '+';
	if(i==2)
		return '-';
	if(i==3)
		return '*';
	if(i==4)
		return '/';
}
void showithpar(parenthesis& par,double digit[],int method[])
{
	for(int i=0;i<digitnum+1;i++)
	{
		if(i==par.left)
			cout<<'(';

		if(i<digitnum)
			cout<<digit[i];
		if(i==par.right-1)
			cout<<')';
		if(i<digitnum-1)
			cout<<num2char(method[i]);
	}
	cout<<" ="<<expect<<endl;
}

     主函数为:

int _tmain(int argc, _TCHAR* argv[])
{
	int n_temp=0;
	double digit[digitnum]={5,5,5,5,5};
	int method[digitnum-1]={0},count=0;
	double expect_temp=0;
	for(int i1=1;i1<=4;i1++)
		for(int i2=1;i2<=4;i2++)
			for(int i3=1;i3<=4;i3++)
				for(int i4=1;i4<=4;i4++)
				{
					method[0]=i1; method[1]=i2; method[2]=i3; method[3]=i4;
					expect_temp=calculate(digit,method,digitnum-1);
					if(expect==expect_temp)
					{
						cout<<"find the "<<++count<<" condition that satisfy the requirements:\n";
						cout<<digit[0]<<num2char(i1)<<digit[1]<<num2char(i2)<<digit[2]<<num2char(i3)
							<<digit[3]<<num2char(i4)<<digit[4]<<"="<<expect<<endl;
					}
				}
				count=0;
				int count_temp=0;
				cout<<endl<<"if have the parenthesis:\n";
				parenthesis par={0,0};
				for(par.left=0;par.left<digitnum;par.left++)
					for(par.right=par.left+2;par.right<=digitnum;par.right++)
					{
						
						if(par.left==0&&par.right==digitnum)
							continue;
						for(int i1=1;i1<=4;i1++)
							for(int i2=1;i2<=4;i2++)
								for(int i3=1;i3<=4;i3++)
									for(int i4=1;i4<=4;i4++)
									{
										method[0]=i1; method[1]=i2; method[2]=i3; method[3]=i4;
										if(check(par,method))
											continue;
										double* p_dig=new double[par.right-par.left];
										int* p_met=new int[par.right-par.left-1];
										for(int i=0;i<par.right-par.left;i++)
											*(p_dig+i)=digit[i+par.left];
										for(int i=0;i<par.right-1-par.left;i++)
											*(p_met+i)=method[par.left+i];
										expect_temp=calculate(p_dig,p_met,par.right-par.left-1);

										if(par.left>=1&&method[par.left-1]==4)
										{
											if(expect_temp==0)
												continue;
										}

										double* p_dig1=new double[digitnum-(par.right-par.left)+1];
										int* p_met1=new int[digitnum-(par.right-par.left)];
										for(int i=0;i<par.left;i++)
											*(p_dig1+i)=digit[i];
										*(p_dig1+par.left)=expect_temp;
										for(int i=par.right;i<digitnum;i++)
											*(p_dig1+par.left+i-par.right+1)=digit[i];
										for(int i=0;i<par.left;i++)
											*(p_met1+i)=method[i];
										for(int i=par.right-1;i<digitnum-1;i++)
											*(p_met1+par.left-1+(i-par.right+2))=method[i];
										expect_temp=calculate(p_dig1,p_met1,digitnum-(par.right-par.left));

										if(expect_temp==expect)
										{
											cout<<"find the "<<++count<<" condition that satisfy the requirements:\n";
											showithpar(par,digit,method);
										}
										delete[] p_dig;
										delete[] p_met;
										delete[] p_dig1;
										delete[] p_met1;
									}

					}
					char ch;
					cout<<"please input a char:\n";
					cin.get(ch);
					return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值