回溯法求排列问题

问题:

输出n的全排列

1. 问题描述: 输出自然数1到n的所有不重复的排列,即n的全排列。

2. 问题分析: 
(1) 解空间: n的全排列是一组n元一维向量(x1, x2, x3, ... , xn),搜索空间是:1<=xi<=n i=1,2,3,...,n 

(2) 约束条件: xi互不相同。技巧:采用"数组记录状态信息", 设置n个元素的一维数组d,其中的n个元素用来记录数据1-n的使用情况,已经使用置0,未使用置1

#include<iostream>
#include<memory>
using namespace std;
int count=0;//解个数
int n;//输入数据
int *a ;//解向量
int *d ;//解状态

void clear( )
{
    for(int i=1;i<=n+1;i++)
    {
        d[i]=0;
    }
}

void output()//第0个不存
{
    for(int i=1;i<=n;i++)
        cout<<a[i]<<ends;
    cout<<endl;
}


void tryArrangement(int k) { for(int i=1;i<=n;i++) { if(d[i]==0) { a[k]=i; d[i]=1; } else { //表明已用过 continue; } if(k<n) //没搜索到底 { tryArrangement(k+1); } else { count++; output(); } d[a[k]]=0; //回溯 } } int main() { cin>>n; a=new int[n+5];//解向量 d=new int[n+5];//解状态 clear( ); tryArrangement(1); }

最开始是这样置d[ ]为0的:

memset(d,0,sizeof(d));

 不行,为什么?

记住,memset是按字节赋值的,第3个参数指定要赋值的字节的大小,应该改成:

 memset(d,0,sizeof(int)*n);

算法说明:k为当前处理的第k个元素。上面的复杂度为O(n^n),不是一个好的算法,因此不可能用它去搜索排序树。

调试分析

k=1 if(d[1]==0) true a[1]=1; d[1]=1 try(2)
k=2 if(d[2]==0) a[2]=2 d[2]=1 try(3)
k=3 if(d[3]==0) a[3]=3; d[3]=1;
3==n; count=1; output 1 2 3

d[3]=0;
} 跳到for( )处运行 F11运行都函数末尾,
F11又跳到try(3) k=2 d[a[2]]=0
} 跳到For处运行
if(d[3]==0) a[2]=3 d[3]=1;
if(k<3) try(3)

 我的代码:

void perm(int n,int r)
{
    int k=1;
    a[k]=0;
    while(k>0)
    {
        a[k]=a[k]+1;
        while(a[k]<=n && !check(k))  
        {
            a[k]++;
        }
        if(a[k]<=n)
        {
            if(k==n)
            {
                for(int i=1;i<=n;i++)
                    cout<<a[i]<<ends;
                cout<<endl;
                count++;
                 
                
            }
            else
            {
                k++;
                a[k]=0;
            }
        }
        else
        {
            a[k]=0;
            k--;
        }
    }
}

可以输出全部排列

另一种解法==也是搜索排列树的算法框架。

设计:根据全排列的概念,定义数组初始值为(1,2,3,4,。。n),这是全排列的一种结果,然后通过数据间的交换,则可产生所有不同的排列:

#include<iostream>
using namespace std;

int a[100],n,s=0;

void output()
{
    for(int j=1;j<=n;j++)
        cout<<a[j]<<ends;
    cout<<endl;
}

void  tryArrange(int k)
{
    int j;
    if(k>n)
    {
        output();
    }
    else
        for(j=k;j<=n;j++)
        {
            swap(k,j);
            tryArrange(k+1);
            swap(k,j); //回溯时,恢复原来的排列
        }
}


int main()
{
    int i;
    cin>>n;
    for(i=1;i<=n;i++)
        a[i]=i;
    tryArrange(1);
    cout<<"换行符"<<"s="<<s;
}

注意c++try是关键字。swap在ios文件中。

原文地址:https://www.cnblogs.com/youxin/p/2592633.html