回溯法解决组合与数的问题(递归与非递归算法)

#include <iostream>
using namespace std;
const int MAX=10;
int a[MAX];
void com(int n ,int m,int s)    //s表示当前被选元素的下标
{
    if(s==m+1)    
    {
        for(int i=1;i<=m;i++)
            cout<<a[i]<<" ";
        cout<<endl;
        return;
    }
    for(int i=a[s-1]+1;i<n-(m-s)+1;i++)
    {
        a[s]=i;
        com(n,m,s+1);
    }
}
int main()
{
    a[0]=0;
    com(5,3,1);
    return 0;
}


//非递归算法
void comb_back(int m,int r)
{
    int *a = new int[r];//创建一个新数组存储构成组合的3个数
    int i,j,k=0;
    i=0,a[i]=1;
    do{
//a[i]-i<+m-r+1 是判断a[i]的值是否在范围之内如i=0时,a[i]最大可以为倒数第r个数,这样本组数的最大值才不至于大过m
        if(a[i]<=m-r+1+i)
        {
            if(i==r-1)  //到了最底层,就一直运行这一分支
            {
                cout<<"第"<<++k<<"组:  ";
                for(j=0;j<r;j++)    
                    cout<<a[j];//打印每个组合中的数字
                cout<<endl;
                a[i]++;
                continue;
            }
            i++;            //前进到下一层试探,深搜
            a[i]=a[i-1]+1;
        }else{                //回溯到上一层进行试探
            if(i==0)
                return;        //已经找到了所有层的解
            a[--i]++;        //前一层的数字增加1,继续进行向前试探,其总共就r层
        }    
    }while(1);
    delete []a;
}
int main()
{
    comb_back(5,3);
}

ps..

因为a[i]-i<=m-r+1
所以  a[i]<=m-r+i+1
也就是说m-r+i+1是a[i]上限呀!至于下限就不要考虑了!为什么呢?因为这种组合有一个规律就是后一个数至少比前一个数大1(如下),向前试探是在前一个数的基础上的:a[i]=a[i-1]+1 

比如:comb_back(5,3)
a[0]的范围是1 (a[0]=1)      到3 (m-r+i+1=5-3+0+1=3)
a[1]的范围是2 (a[1]=a[0]+1) 到4 (m-r+i+1=5-3+1+1=4)
a[2]的范围是3 (a[2]=a[1]+1) 到5 (m-r+i+1=5-3+2+1=5)

a[0] a[1] a[2]
  1    2    3
  1    2    4
  1    2    5
  1    3    4
  1    3    5
  1    4    5

  2    3    4

  2    3    5
  2    4    5

  3    4    5


方法二:

#include <stdio.h>
#define N 100
int a[N];
int last;

void zuhe(int m,int k)//从m个元素中取出k个元素的组合
{
	int i,j;
	for(i=m; i>=k; i--)
	{
		a[k]=i;//最后一个位置的元素可以取m,m-1,m-2.....k
		if(k>1) zuhe(i-1,k-1);//递归调用
		else
		{
			for(j=1;j<=last;j++)
				printf("%d ",a[j]);
			printf("\n");
		}
	}
}
void main()
{
	int n,m;
	printf("请输入Cn,m中n与m的值:");
	scanf("%d%d",&n,&m);
	if(n>100)
		printf("数字太大了!");
	last=m;
	zuhe(n,m);    
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值