C++回溯法实例分析
本文实例讲述了C++的回溯法,分享给大家供大家参考之用。具体方法分析如下:
一般来说,回溯法是一种枚举状态空间中所有可能状态的系统方法,它是一个一般性的算法框架。
解向量a=(a1,a2,...,an),其中每个元素ai取自一个有限序列集Si,这样的解向量可以表示一个排列,其中ai是排列中的第i个元素,也可以表示子集S,其中ai为真当且仅当全集中的第i个元素在S中;甚至可以表示游戏的行动序列或者图中的路径。
在回溯法的每一步,我们从一个给定的部分解a={a1,a2,...,ak}开始,尝试在最后添加元素来扩展这个部分解,扩展之后,我们必须测试它是否为一个完整解,如果是的话,就输出这个解;如果不完整,我们必须检查这个部分解是否仍有可能扩展成完整解,如果有可能,递归下去;如果没可能,从a中删除新加入的最后一个元素,然后尝试该位置上的其他可能性。
用一个全局变量来控制回溯是否完成,这个变量设为finished,那么回溯框架如下,可谓是回溯大法之精髓与神器
boolfinished=false;
voidbackTack(intinput[],intinputSize,intindex,intstates[],intstateSize)
{
intcandidates[MAXCANDIDATE];
intncandidates;
if(isSolution(input,inputSize,index)==true)
{
processSolution(input,inputSize,index);
}
else
{
constructCandidate(input,inputSize,index,candidates,&ncandidates);
for(inti=0;i<ncandidates;i++)
{
input[index]=candidates[i];
backTack(input,inputSize,index+1);
if(finished)
return;
}
}
}
不拘泥于框架的形式,我们可以编写出如下代码:
#include<iostream>
usingnamespacestd;
charstr[]="abc";
constintsize=3;
intconstructCandidate(bool*flag,intsize=2)
{
flag[0]=true;
flag[1]=false;
return2;
}
voidprintCombine(constchar*str,bool*flag,intpos,intsize)
{
if(str==NULL||flag==NULL||size<=0)
return;
if(pos==size)
{
cout<<"{";
for(inti=0;i<size;i++)
{
if(flag[i]==true)
cout<<str[i]<<"";
}
cout<<"}"<<endl;
}
else
{
boolcandidates[2];
intnumber=constructCandidate(candidates);
for(intj=0;j<number;j++)
{
flag[pos]=candidates[j];
printCombine(str,flag,pos+1,size);
}
}
}
voidmain()
{
bool*flag=newbool[size];
if(flag==NULL)
return;
printCombine(str,flag,0,size);
delete[]flag;
}
采用回溯法框架来计算字典序排列:
#include<iostream>
usingnamespacestd;
charstr[]="abc";
constintsize=3;
voidconstructCandidate(char*input,intinputSize,intindex,char*states,char*candidates,int*ncandidates)
{
if(input==NULL||inputSize<=0||index<0||candidates==NULL||ncandidates==NULL)
return;
boolbuff[256];
for(inti=0;i<256;i++)
buff[i]=false;
intcount=0;
for(inti=0;i<index;i++)
{
buff[states[i]]=true;
}
for(inti=0;i<inputSize;i++)
{
if(buff[input[i]]==false)
candidates[count++]=input[i];
}
*ncandidates=count;
return;
}
boolisSolution(intindex,intinputSize)
{
if(index==inputSize)
returntrue;
else
returnfalse;
}
voidprocessSolution(char*input,intinputSize)
{
if(input==NULL||inputSize<=0)
return;
for(inti=0;i<inputSize;i++)
cout<<input[i];
cout<<endl;
}
voidbackTack(char*input,intinputSize,intindex,char*states,intstateSize)
{
if(input==NULL||inputSize<=0||index<0||states==NULL||stateSize<=0)
return;
charcandidates[100];
intncandidates;
if(isSolution(index,inputSize)==true)
{
processSolution(states,inputSize);
return;
}
else
{
constructCandidate(input,inputSize,index,states,candidates,&ncandidates);
for(inti=0;i<ncandidates;i++)
{
states[index]=candidates[i];
backTack(input,inputSize,index+1,states,stateSize);
}
}
}
voidmain()
{
char*candidates=newchar[size];
if(candidates==NULL)
return;
backTack(str,size,0,candidates,size);
delete[]candidates;
}
对比上述两种情形,可以发现唯一的区别在于全排列对当前解向量没有要求,而字典序对当前解向量是有要求的,需要知道当前解的状态!
八皇后回溯法求解:
#include<iostream>
usingnamespacestd;
intposition[8];
voidconstructCandidate(int*input,intinputSize,intindex,int*states,int*candidates,int*ncandidates)
{
if(input==NULL||inputSize<=0||index<0||candidates==NULL||ncandidates==NULL)
return;
*ncandidates=0;
boolflag;
for(inti=0;i<inputSize;i++)
{
flag=true;
for(intj=0;j<index;j++)
{
if(abs(index-j)==abs(i-states[j]))
flag=false;
if(i==states[j])
flag=false;
}
if(flag==true)
{
candidates[*ncandidates]=i;
*ncandidates=*ncandidates+1;
}
}
/*
cout<<"ncandidates="<<*ncandidates<<endl;
system("pause");*/
return;
}
boolisSolution(intindex,intinputSize)
{
if(index==inputSize)
returntrue;
else
returnfalse;
}
voidprocessSolution(int&count)
{
count++;
}
voidbackTack(int*input,intinputSize,intindex,int*states,intstateSize,int&count)
{
if(input==NULL||inputSize<=0||index<0||states==NULL||stateSize<=0)
return;
intcandidates[8];
intncandidates;
if(isSolution(index,inputSize)==true)
{
processSolution(count);
}
else
{
constructCandidate(input,inputSize,index,states,candidates,&ncandidates);
for(inti=0;i<ncandidates;i++)
{
states[index]=candidates[i];
backTack(input,inputSize,index+1,states,stateSize,count);
}
}
}
voidmain()
{
//初始化棋局
for(inti=0;i<8;i++)
position[i]=i;
intstates[8];
intcount=0;
backTack(position,8,0,states,8,count);
cout<<"count="<<count<<endl;
}
希望本文所述对大家C++程序算法设计的学习有所帮助。