1~n 内排序(递归和回溯)

本文探讨了1~n数字的排列算法,包括递归法和回溯法实现的有序和无序排列,并提供了详细的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:
1~n之内的数字排列,可以全排,或者抽其中m个数排列,带顺序或不带顺序,分别用递归和回溯法编写
(其实全部排列和只排其中的m(m<=n)个数差不多,就是在判别当前位置是否达到n或m,只用改一行代码就行了。重点是这个顺序问题)

一.: 1~n之内的排列,带顺序! A(m,n) 【递归】

分析:这个算法其实很常见,做过几道算法题的大家都懂,每个位置上1~n数全部试一次,然后再判断当前位置上的数跟前面位置的数比较有没有重复,有就换下一个数,没有就递归下一个位置。

//1~n之间抽取n个数进行排列【递归】 
#include<stdio.h>
#define MAXN 1000

int a[MAXN];
int n,m; //n是 几个数进行排列,m是指1~n之间抽取m个数进行排列
int count=0 ;   //共有count种排列方法 
void f(int cur)
{
    int i,j;
    //我的数组是从1开始赋值的,若是0开始,则cur==m就行了 
    if(cur>m)   //注意,在区间取m个数或者全排列的区别就在这里,全排列则改为cur>n 
    {
        count++;
        return ; 
    }
    for(i=1;i<=n;i++)
    {
        int ok=1;
        for(j=1;j<cur;j++) //将当前位置上的数和 前面位置的数进行比较,有重复的话换一个值去赋值
          if(a[j]==i)
          {
            ok=0;
            break;
           } 
        if(ok)
         {
            a[cur]=i;
            f(cur+1);
         }
    }

}


int main()
{
    scanf("%d%d",&n,&m);
    f(1);
    printf("%d\n",count);
    return 0; 

 } 

二. 1~n之内的排列,不在乎顺序!C(m,n) 【递归】

分析:注意到组合与组成顺序无关,约定组合中的组成元素按递增排序。所以把上面代码排序的约束条件修改 :

for(i=a[cur-1]+1;i<n-m+cur;i++)
    a[cur]=i;

循环起点为a[cur-1]+1,即a[cur]的值比a[cur-1]大,避免了元素取相同值的判别!
循环终点为n+cur-m,即a[cur]最大只能取n+cur-m,为后面m-cur个元素a[cur+1],…….a[m]留下取值空间(后面的元素取值比a[cur]大,且最大取到n)
注意:上个程序数组下标直接从1开始赋值,在它的基础上修改为这个函数,优势就出来了!!!

//1~n之间抽取n个数进行排列【递归】 
#include<stdio.h>
#define MAXN 1000

int a[MAXN];
int n,m; //n是 几个数进行排列,m是指1~n之间抽取m个数进行排列
int count=0 ;   //共有count种排列方法 
void f(int cur)
{
    int i,j;
    //我的数组是从1开始赋值的,若是0开始,则cur==m就行了 
    if(cur>m)   //注意,在区间取m个数或者全排列的区别就在这里,全排列则改为cur>n 
    {
        count++;
        return ; 
    }
    a[0]=0;
    for(i=a[cur-1]+1;i<=n-m+cur;i++)      //无需再判断是否有重复值,这是递增的,不存在 
    {
        a[cur]=i;
        f(cur+1);
    }    
}


int main()
{
    scanf("%d%d",&n,&m);
    f(1);
    printf("%d\n",count);
    return 0; 

 } 

这个这个要开始讨论回溯了,先考虑1~n的全排列:

三 . 1~n之内的排列,带顺序! A(n,n) 【回溯】

分析:首先从a[1]=1开始,逐步给a[cur](1<=cur<=n)赋值,每一个a[cur]赋值从一开始递增到n,直至a[n]赋值,判断:
1。若cur=n,且ok=1即无重复,则为一组解
2。若cur《n且ok=1,表明还不到9个数字,则下一个a[i]从1开始赋值继续
3.。若a[n]=n,则返回前一个数组元素,a[n-1]增1赋值(a[n]从1开始再一个个值的试),直到a[1]=9为止,已无法返回,意味全部测试完,可结束

#include<stdio.h>
int main()
{
    int a[100];
    int n,i,count=0,ok,cur;
    scanf("%d",&n);
    a[cur=1]=1;
    while(1)
    {
        ok=1;
        for(i=1;i<cur;i++)     //判断当前位置与之前的位置上的数是否有重复 
          if(a[i]==a[cur])
          {
            ok=0;
            break;
          }
        if(cur==n && ok)
           count++;         //种类数 


        if(cur<n && ok)  //不到n个数,往后赋值,接着赋值 
        {
            cur++;
            a[cur]=1;
            continue; 
         }
        while(a[cur]==n && cur>1)   //往前回溯 
          cur--;
        if(a[cur]==n && cur==1)  //结束标志 
          break; 
        else
          a[cur]++;
    }
    printf("%d\n",count);
    return 0;
}

四。 1~n之内的排列,不在乎顺序!C(m,n) 【回溯】

分析:首先起点为a[cur-1]+1,即a[cur]的值比a[cur-1]大,逐步给a[cur](1<=cur<=n)赋值,直至a[m]赋值,判断:
1。若cur《m,表明还不到m个数字,则下一个a[cur]继续从a[cur-1]+1开始赋值
2。若cur=m,则为一组解
3.。若cur>1且a[cur]=n+cur-m时,即该位置的数已取到最大值,往前回溯
4..。若cur=1且a[cur]=n-cur+m,即所以可能已取完,退出循环,否则该位置的数加1,继续判断

#include<stdio.h>
#include<stdlib.h>
int main()
{
    int a[100];
    int n,m,count=0,cur;
    scanf("%d%d",&n,&m);  //n个数中选取m个数进行无顺序排列,要是在n个数中选n个数无顺序排列就没啥意思,答案就是1 
    a[0]=0;cur=0;
    while(1)
    {
        if(cur<m)  //不到m个数,往后赋值,接着赋值 
        {
            cur++;
            a[cur]=a[cur-1]+1;
            continue; 
         }      
        if(cur==m)
           {count++;         //种类数 
            for(int i=1;i<=cur;i++)
              printf("%d",a[i]);
              printf("\n");system("PAUSE");
          }
        while(a[cur]==n+cur-m && cur>1)   //往前回溯 
          cur--;
        if(cur==1 && a[cur]==n+cur-m)  //结束标志 :递增排列的,a[1]最多取到n+cur-m,还要给剩下的m-cur位数赋值 
          break;
        else
          a[cur]++; 
    }
    printf("%d\n",count);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值