从n个自然数中找出r个数的组合(5个自然数中寻找3个)

穷举法:

void main(){
int n=5;
int j,i,k;
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
{
for( k=1;k<=n;k++)
if(j<=i||k<=j) continue;//如果j<=i或者k<=j,那么舍弃当前组合
else {
cout<<i<<j<<k<<" ";
}
}
}
}

穷举法通过列举所有情况,然后通过一系列的条件判断是否适合,最后输出符合条件的组合。

递归法:

int a[5];
void digui(int n,int r)
{
if(r==0)
{ 
for(int j=3;j>r;j--)
	{
	cout<<a[j];
	}
cout<<" ";
}
else 
{for(int i=n;i>=r;i--)
{
a[r]=i;
digui(i-1,r-1);
}
}
}
void main()
{
int n=5;
int r=3;
digui(5,3);
}

先取得第三个数字的值,再确定第二个数字的值,最后确定第一个数字的值。递推规律为(5,3)——>(4,2)——>(3,1)(代表了取值范围的变化)。其中的一个规律是要保证第二个取得的数字要小于第一个数字,第三个取得数字要小于第二个数字,当所有数字都确定了就输出组合。比如代码中的递归代用digui(i-1,r-1)就不能换成digui(n-1,r-1)。因为实时变化的是 i 值,比如第二个数值取值范围在(4,2),n=4,当i=2时,第二个数值取值为2,n依然等于4,下一个递归调用里面的n就为3,第三个数可以取值为2,最后的组合可以是522等形式,甚至能形成333组合。所以需要保证递归传入的n值应该为 i-1 而不是 n-1 。

回溯法:

int n=5;
int r=3;
int a[4];
bool is_huisu(int k)
{
for(int j=1;j<k;j++)
{
if(a[j]>=a[k])
return false;
}
return true;
}
void HuiSu(int k)
{
	if(k==r+1)
	{
for(int o=1;o<k;o++)
{
cout<<a[o];
}
cout<<" ";
}
else
for(int i=1;i<=n;i++)
{ 
	a[k]=i;
 if(is_huisu(k))
   HuiSu(k+1);
}  
}


void main(){
int k=1;
HuiSu(1);
}

回溯法是从试探性的角度,先确定第一个值,然后确定第二个值,对第三个数值进行遍历,最后输出,然后回溯重新确定第二个值,再对第三个数值遍历,以此类推。回溯法会试探性的对所有值进行判定,然后根据选取条件,选择合适的数值。与穷举法不同的是,回溯法会先对这个值进行条件判定,只选取符合条件的值,再进行下一步操作。

以上代码,都可以加入头文件 #include<iostream.h>,再进行编译。

以上,祝好!

猜你喜欢

转载自blog.csdn.net/weixin_42552233/article/details/81056854