本文由苏振元于2009年11月16日下午17:00发表于www.csdn.net,更新与2009年11月16日下午17:12
版权声明:可以任意转载,转载时请务必以超链接形式标明文章原始出处和作者信息及本版权声明。
经过近半月的冥思苦想和search 资料,终于把回溯问题解决了,就是设置一个游标cur,用来指示当前正在运算的位置,然后设置一个回溯标志backflag,用于决定给数赋初始值还是在原来的数的基础上进行加一操作(这就是回溯了)。
之前一直把问题想的很复杂,涉及到较多的数据结构问题。就是用堆栈来记录已经赋过值的数,每次从堆栈中取数,并加一……最终,在这种算法中并没有太多的想法,也就丢弃了,另辟蹊径,没想到居然成功了!
下面的就是我写的代码(新鲜出炉的,可是我早上十点钟写到十三点,然后调试到21:30,终于完成了!不过,代码还有很多地方不是很严谨,现在再考虑有没有必要把它做成可以解任何加法的算式密码问题,还是只针对这个问题就算了):
#include<iostream>
using namespace std;
#include<string.h>
#include<stdlib.h>
#include<stdio.h>
#include<time.h>
const int N=10;
char strx[N],stry[N],strz[N];
int x[N],y[N],z[N];
char getchar(int type, int index)
{
if(type==-1) //在x数组中
return strx[index];
else if(type==0)
return stry[index];
else
return strz[index];
}
int search(char ch, int num, int xi,int yi,int zi)
{
int lenx=(int)strlen(strx); //字符串strx的长度
int leny=(int)strlen(stry); //字符串stry的长度
int lenz=(int)strlen(strz); //字符串strz的长度
int i;
for(i=xi;i<lenx;i++) //在strx串中搜索。
{
if((ch==strx[i] && num!=x[i]) || (ch!=strx[i] && num==x[i]))
return 0;
}
for(i=yi;i<leny;i++) //在stry串中搜索。
{
if((ch==stry[i] && num!=y[i]) ||(ch!=stry[i] && num==y[i]) )
return 0;
}
for(i=zi;i<lenz;i++) //在strz串中搜索。
{
if( (ch==strz[i] && num!=z[i]) ||(ch!=strz[i] && num==z[i]))
return 0;
}
return 1;
}
int islegal(int type, int num,int index,int xi,int yi, int zi) //要检查的数字所在的字符串-1:x,0:y,1:z,要检查数字的下标,搜索范围xi,yi,zi~len
{
char ch;
//判断该
if(index==0 )
{
if( (type==-1 && x[0]==0 )|| (type==0 && y[0]==0) || (type==1 && z[0]==0) )
return 0;
else
{
ch=getchar(type,index);
//
cout<<" ch = "<<ch<<'/n';
return search(ch,num,xi,yi,zi);
}
}
else
{
//
cout<<" type= "<<type<<" index="<<index<<'/n';
ch=getchar(type,index);
//
cout<<" ch = "<<ch<<'/n';
return search(ch,num,xi,yi,zi);
}
return 1;
}
void solve()
{
int lenx=(int)strlen(strx); //字符串strx的长度
int leny=(int)strlen(stry); //字符串stry的长度
int lenz=(int)strlen(strz); //字符串strz的长度
//
cout<<lenx<<" -> "<<leny<<" -> "<<lenz<<'/n';
int min,max;
min=(lenx>=leny)?leny:lenx; //记录较短串的长度
max=(lenx<leny)?lenx:leny; //记录较长串的长度 用于处理超出较短串部分的字符。
int backflag=0;//回溯标志,0表示不是回溯,1表示回溯。
int cur=0;//当前以运算列数。把strx和stry对应的两个字符看做一列。
int *carry=new int[lenz]; //进位的最大长度也就是和的长度
for(int k=0;k<lenz;k++)
{
carry[k]=0;
//
cout<<carry[k];
}
//
cout<<'/n';
int xi=lenx-1;
int yi=leny-1;
int zi=lenz-1;
x[lenx-1]=0;
for(cur=0;cur<max && x[lenx-1]<10;cur++)
{
xi=lenx-cur-1;
yi=leny-cur-1;
zi=lenz-cur-1;
if( backflag == 0 ) //不是回溯回来的,起始值0;
{
//
cout<<"107:cur = "<<cur<<" xi = "<<xi<<" yi = "<<yi<<" zi = "<<zi<<'/n';
x[ xi ] = 0;
}
for(;x[ xi ] < 10; x[ xi ] ++)
{
if(islegal(-1,x[xi],xi,xi+1,yi+1,zi+1)==1)
{
//不是回溯回来的,出起始值-1;为了下面y[yi]++做准备,这样回溯回来时,y[yi]的值就会增加。当y[yi]的值增加到10时,就会引起x[xi]的改变
if( backflag == 0 )
y[yi]=-1;
for( y[yi]++; y[yi]<10;y[yi]++)
{
if(y[yi]==x[xi])
continue;
if(islegal(0,y[yi],yi,xi,yi+1,zi+1) == 1) //找到一个符合条件的x,y;
{
//
cout<<" "<<zi<<" "<<carry[zi-1]<<'/n';
z[zi]=(x[xi]+y[yi]+carry[zi])%10;
carry[zi-1]=(int)((x[xi]+y[yi]+carry[zi])/10);
if(islegal(1,z[zi],zi,xi,yi,zi+1)==1)
{
//
cout<<"131: cur = "<<cur<<" -> "<<x[xi]<<"+"<<y[yi]<<"+"<<carry[zi]<<"="<<z[zi]<<"……"<<carry[zi-1]<<'/n';
//
cout<<"ifleagel(z)="<<islegal(1,z[zi],zi,xi,yi,zi)<<'/n';
break;
}
}
//
cout<<y[zi]<<'/n';
}
if(y[yi]<10) //说明找到符合运算规则的一列了。那么cur该加一了;
break;
}
backflag=0;
}
//
cout<<" cur "<<cur<<" /n";
//
system("Pause");
//是否要回溯
if( x[xi]>9 ) //x[xi]大于9了,回溯到后一列,置backflag=1;
{
backflag=1;
cur-=2; //因为for循环中还有一个加一操作,所以这里应该是减二。
continue;
}
else
{
backflag=0; //符合条件,置backflag=0,表示进入下一行了。没有进行回溯。
}
//
cout<<"161: cur= "<<cur<<" min = "<<min<<" max = "<<max<<'/n';
for(;cur>=min && cur<max;cur++)//处理超出部分,如果只是为了解决send+more+money问题,该段代码不起作用。
{
cout<<"*";
if(lenx>leny) //strx比stry长,那么该处理的就是strx。
{
xi=lenx-cur-1;
zi=lenz-cur-1;
if(backflag==0) //不是回溯进来的。
x[xi]=0;
for(;x[xi]<10;x[xi]++)
{
if( islegal( -1,x[xi],xi,xi+1,yi+1,zi+1 ) ==1 )
{
z[zi]=(x[xi]+carry[zi])%10;
carry[zi-1]=(int)((x[xi]+carry[zi])/10);
if(islegal(1,z[zi],zi,xi,yi,zi+1)==1)
break;
}
}
if(x[xi]>10)
{
cur-=2;//因为for循环中还有一个加一操作,所以这里应该是减二。
backflag=1;
break;
}
else
{
backflag=0;
break;
}
}
else
{
yi=lenx-cur-1;
zi=lenz-cur-1;
if(backflag==0) //不是回溯进来的。
y[yi]=0;
for(;y[yi]<10;y[yi]++)
{
if( islegal(1, y[yi],yi,xi,yi+1,zi+1) ==1 )
{
z[zi]=(y[yi]+carry[zi])%10;
carry[zi-1]=(int)((y[yi]+carry[zi])/10);
if(islegal(1,z[zi],zi,xi,yi,zi+1)==1)
break;
}
}
if(y[yi]>10)
{
cur-=2;//因为for循环中还有一个加一操作,所以这里应该是减二。
backflag=1;
break;
}
else
{
backflag=0;
break;
}
}
}
//
cout<<" carry[ "<<zi<<" ]= "<<carry[zi]<<'/n';
//
cout<<""<<lenz-max<<'/n';
//
cout<<"227: cur= "<<cur<<" min = "<<min<<" max = "<<max<<'/n';
if(cur>=max-1 && lenz>max)
{
//
cout<<"231:cur = "<<cur<<" , lenz = "<< lenz<<", max= "<<max<<'/n';
//
cout<<"232:"<<xi<<" -> "<<yi<<" -> "<<zi<<'/n';
if(carry[0]!=0)
{
z[0]=carry[0];
if(islegal(1,z[0],0,0,0,1)==1) //不用回溯
break;
else
{
backflag=1;
cur-=1;
}
}
else
{
backflag=1;
cur-=1;
}
}
//
cout<<"cur"<<cur<<'/n';
}
//cout<<"cur "<<cur<<'/n';
//cout<<" carry[ "<<zi<<" ]= "<<carry[zi]<<'/n';
int i=0;
/*
for(i=0;i<lenz;i++)
cout<<carry[i]<<" ";
cout<<'/n';
*/
cout<<" ";
for(i=0;i<lenx;i++)
cout<<" "<<x[i];
cout<<'/n';
cout<<"+";
for(i=0;i<leny;i++)
cout<<" "<<y[i];
cout<<'/n';
cout<<"----------/n";
for(i=0;i<lenz;i++)
cout<<z[i]<<" ";
cout<<'/n';
}
int check()
{
int lenx=(int)strlen(strx); //字符串strx的长度
int leny=(int)strlen(stry); //字符串stry的长度
int lenz=(int)strlen(strz); //字符串strz的长度
int min,max;
min=(lenx>=leny)?leny:lenx; //记录较短串的长度
max=(lenx<leny)?lenx:leny; //记录较长串的长度 用于处理超出较短串部分的字符。
if( lenz-max != 1 )
return 0;
else
return 1;
}
int main()
{
clock_t start,finish;
freopen("data.txt","r",stdin);
//freopen("dout.txt","w",stdout);
cin>>strx>>stry>>strz;
cout<<strx<<'/n'<<stry<<'/n'<<strz<<'/n';
start=clock();
if(check()==1)
{
solve();
}
else
{
cout<<"你输入的算式不符合加法规则!和的长度只能比加数中长度最长的大一!";
}
finish=clock();
cout<<"共花费的时间为:"<<(long)(finish)-(long)(start)<<"ms/n";
return 0;
}
data.txt中的内容就是
send
more
money
这个文件只是用来解决我懒惰的问题,不想每次调试的时候倒要输入这个算式。
输出结果为: