全排列的算法(六)——回溯法

全排列的生成算法(六)——回溯法

回溯法通常是构造一颗生成树。以3个元素为例;树的节点数据可取值是123。如果某个节点为0,则表示尚未取值。

初始状态是(000),第1个元素值可以分别挑选123,因此扩展出3个子结点。用相同方法找出这些结点的第2个元素的可能值,如此反复进行,一旦出现新结点的3个数据全非零,那就找到了一种全排列方案。当尝试了所有可能方案,即获得了问题的解答。

回溯法有非递归和递归两种形式。递归形式的程序代码比较简洁,但是递归会带来运行时间和内存的额外消耗,效率较低。非递归形式的回溯法效率要高一些,但程序代码比较复杂。

 

//回溯(非递归)

//输入:排列元素个数n

//输出:n个元素的全体排列

#include <iostream>

#include <iomanip>

using namespace std;

void output(int *,int);

void backdate(int *,int);

int total;

int main(void)

{

freopen(“in.txt”,”r”,stdin);

//
freopen(“out.txt”,”w”,stdout);

int n,*p;

while(cin>>n)

{

p=new int[n];

fill_n(p,n,0);

total=0;

backdate(p,n);

}

return 0;

}

 

void backdate(int *p,int n)

int i=0,j=1;                                 //i是排列元素的序号,j是排列元素所取得值

while(1)

{

while(j<=n)                       //如果p[i]所取得值在可取值范围,继续

{

for(int k=0;k<i;k++)  //p[i]所取得值是否与前面元素的值重复

if(p[k]==j) 

break;

if(k==i)                    //不重复

{

p[i++]=j;          //p[i]取值j       

j=1;                 //继续为下一个排列元素取值

break;

}

j++;                        //换一个

}

if(i==n)                          //如果排列的那个元素都已选定

{

output(p,n);           //输出一个排列

j=n+1;                   //调整最后一个元素的值,准备回溯,找下一个排列

}

if(j>n)                            //当j超出可取值范围

{

j=p[–i]+1;             //回溯

if(i<0)                   //不能回溯

break;          //结束

}

}

}

 

void output(int *p,int n)

{

cout<<setw(5)<<++total<<“:  “;

for(int i=0;i<n;i++)

cout<<setw(2)<<p[i];

cout<<endl;

}

 

 

 

//回溯算法(递归)

//输入:排列元素个数n

//输出:n个元素的全体排列

#include<iostream>

#include <iomanip>

using namespace std;

 

void output(int *,int);

void backdate(int *,int,int);

int total;

int main(void)

{

freopen(“in.txt”,”r”,stdin);

//
freopen(“out.txt”,”w”,stdout);

int n,*p;

while(cin>>n)

{

p=new int[n];

fill_n(p,n,0);

total=0;

backdate(p,n,0);

}

return 0;

}

void backdate(int *p,int n,int k)

if(k==n)                                                //如果n个排列元素的值都已选定

output(p,n);                                  //输出一个排列

else                                                      //否则,继续选择排列元素的值

for(int i=1;i<=n;i++)                     //i是排列元素可取的值 

{

for(int j=0;j<k;j++)               //i是否与已选的元素重复

if(p[j]==i) 

break;

if(j==k)                                //不重复  

{

p[k]=i;                         //p[i]取值i

backdate(p,n,k+1);    //继续

}

}

}

void output(int *p,int n)
{
cout<<setw(5)<<++total<<“:  “;
for(int i=0;i<n;i++)
cout<<setw(2)<<p[i];
cout<<endl;

 

    原文作者:回溯法
    原文地址: https://blog.csdn.net/babynumber/article/details/43924291
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞