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

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

回溯法通常是构造一颗生成树。以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;


 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值