1.递归问题
递归里面用return了,那么函数遇到return 就不走了,是不是就不用归了?
这这个问题比如下面的代码:#include<iostream>
using namespace std;
void Function(int n)
{
if(n == 1)
{
cout<<"n="<<n<<endl;
return;
}
Function(n-1);
cout<<"n="<<n<<endl;
}
int main(){
Function(5);
system("pause");
return 0;
}
输出的结果是1,2,3,4,5
return 对当前函数来说是结束了,对调用它的父函数来说你这个函数执行完成了,父函数就会接着执行下一语句。
没想到父函数马上又遇到一个return,父函数结束了,对爷爷函数来说父函数执行完成了,爷爷函数就接着执行下一个语句
没想到。。。
没想到。。。
也就是说先调用Function(5)---Function(1),输出1,返回;再调用Function(2),输出2,再........
可以看出上面的过程有回溯的味道!回溯就是这样由递归自然形成的!
2.幂集问题
#include<iostream>
using namespace std;
void sub(int start,int num,int data[],bool label[]){
if(start==num){//此时是从0开始的,所以的==num或>=num,表示到叶子了
for(int i=0;i<num;i++){
if(label[i]){
cout<<data[i]<<" ";
}
}
cout<<endl;
return;//此时仅仅是结束了当前的函数,不会退出整个函数,不能少
}
label[start]=true;
sub(start+1,num,data,label);
label[start]=false;
sub(start+1,num,data,label);
}
int main(){
int num=3;
int data[3]={1,2,3};
bool label[3]={false};
sub(0,num,data,label);
system("pause");
return 0;
}
2.全排列问题
#include<iostream>
using namespace std;
void permute(int pos,int num,int data[],int tmp[],bool label[]){
if(pos==num){
for(int i=0;i<num;i++){
cout<<tmp[i];
}
cout<<endl;
//return;//也可以不去掉这一句,但现在还不知道为什么??
}
for(int j=0;j<num;j++){//这个循环其实跟上面的代码类似,只不过上面每层只有两个选择(选或不选),现在每层有num个选择
if(!label[j]){
tmp[pos]=data[j];
label[j]=true;
permute(pos+1,num,data,tmp,label);
label[j]=false;
}
}
}
int main(){
int data[4]={1,2,3,4};
int tmp[4];
int num=4;
bool label[4]={false};
permute(0,num,data,tmp,label);
system("pause");
return 0;
}
#include<iostream>
using namespace std;
int a[4] = {1,2,3,4};
const int N = 4;
void print(){
for(int i = 0; i < N; i++)
cout << a[i] << " ";
cout << endl;
}
void swap(int *a,int i,int j){
int temp;
temp = a[i];
a[i] = a[j];
a[j] = temp;
}
void backtrack(int i){
if(i >= N){
print();
}
for(int j = i; j < N; j++){
swap(a,i,j);
backtrack(i+1);
swap(a,i,j);
}
}
int main(){
backtrack(0);
return 0;
}
求解思想:
排列中每一个数字,都有一次当最前单一缀的机会,
例如: 排列数组 a[]
1.当a[]中只有1个数字的时候,(a[1]={a1})则只有1个数字做单一前缀和后缀,则只有一种(1!=1)可能 a1,直接输出
2.当a[]中只有2个数字的时候,(a[2]={a1,a2}) ,则a1,a2分别有一次机会做单一前缀的机会,(2!=2) ,{a1 ,a2} {a2,a1}
3,当a[]中有3个数字时候,(a[3]={a1,a2,a3}) ,3个数字分别有一次做前缀的机会,则固定一个数字做前缀有3中情况(a1..... a2........ a3........) ,后面2个数字如同情况2.
故有3!=6中排列。
4.当a[]的数字数目大于2情况都如同情况3 。
#include<iostream> using namespace std; void swap(int &a,int &b) { int temp ; temp=a; a=b; b=temp; } void show(int a[],int n) //显示全部数组 { for(int i=0;i<n;i++ ) { cout<<a[i]<<" "; } cout<<endl; } void prim(int a[],int k, int n) //n是这个a[]中有多少个元素 ,k是a[]需要全排列的的坐下标 { if(k==n-1)//不是只有一个元素 而是全排列到最后一个数字时 终止递归的条件 { show(a,n); } else { for(int i=k;i<n;i++) //从k开始时保证交换和递归次数 { swap(a[i],a[k]); //第一次 自己和自己交换即自己是最前单一前缀 交换单一前缀和后缀中的每一个元素 ,让每一个元素都可以做前缀 prim(a,k+1,n); swap(a[i],a[k]); //回溯之后 仍然恢复交换以前的顺序 } } } int main(int argc, char* argv[]) { int a[3]={1,2,3}; prim(a,0,3); system("PAUSE"); return 0; }
这两个问题很有代表性,事实上有许多问题都是从这两个问题演变而来的。第一个问题,它穷举了所有问题的子集,这是所有第一种类型的基础,第二个问题,它给出了穷举所有排列的方法,这是所有的第二种类型的问题的基础。理解这两个问题,是回溯算法的基础.
3.子集和问题
#include<iostream>
using namespace std;
void SumofSub(int start,int data[],int num,int sum,int label[]){
if(start>=num){
if(sum==0){//
for(int i=0;i<num;i++){
if(label[i])
cout<<data[i]<<" ";
}
cout<<endl;
}
return;//不能少
}
if(data[start]<=sum){
label[start]=true;
SumofSub(start+1,data,num,sum-data[start],label);
}
label[start]=false;
SumofSub(start+1,data,num,sum,label);
}
int main(){
int data[]={1,2,3,4,5};
int num=5;
int sum=7;
int label[5];
SumofSub(0,data,num,sum,label);
system("pause");
return 0;
}
4.八皇后问题
八皇后问题是一个以国际象棋为背景的问题:如何能够在 8×8 的国际象棋棋盘上放置八个皇后,使得任何一个皇后都无法直接吃掉其他的皇后?为了达到此目的,任两个皇后都不能处于同一条横行、纵行或斜线上(2)如果检查了该行所有的位置均不能放置一个皇后,说明上一行皇后放置的位置无法让所有的皇后找到自己合适的位置,因此就要回溯到上一行,重新检查该皇后位置后面的位置
#include<iostream>
#include<cstdlib>
using namespace std;
//注意abs是定义在cstdlib库中的
bool check(int i,int column[]){
for(int j=0;j<i;j++){
if(column[j]==column[i]||abs(column[i]-column[j])==(i-j)){//斜率等于±1
return false;
}
}
return true;
}
//start表示搜索的行,column表示该行的所放的列
void eightQueen(int start,int column[],int &sum){
if(start>=8){
for(int j=0;j<8;j++){
cout<<column[j]<<" ";
}
cout<<endl;
sum++;
return;
}
for(int j=0;j<8;j++){
//column[start]=j;
if(check(start,column)){
column[start]=j;
eightQueen(start+1,column,sum);
}
}//end for
}
int main(){
int column[8];
int sum=0;
eightQueen(0,column,sum);
cout<<sum<<endl;
system("pause");
return 0;
}
错误的关键就是column[start]=j写在了if内部,导致column[]没有更新,所以check()会无法判别
正切的是该句在外面
结果有92种。