每日一小题回溯

本文详细阐述了一种算法设计方法,针对n个数中选取r个数的组合问题,通过分析数据特点,确定了搜索过程中元素索引的递推规则,并给出了回溯策略。通过代码实现和理论证明,展示了如何有效地在一组有序数组中找到符合条件的组合。
摘要由CSDN通过智能技术生成

题目描述:找n个数中r个数的组合。
1、算法设计 先分析数据的特点,以n=5,r=3为例
其中n为组合中的最大值,r为组合个数
在数组a中: a[1] a[2] a[3]
5 4 3
5 4 2
5 4 1
5 3 2
5 3 1
5 2 1
4 3 2
4 3 1
4 2 1
3 2 1

分析数据的特点,搜索时依次对数组(一维向量)元素a[1]、a[2]、a[3]进行尝试,
a[ri] i1——i2
ri为数组索引,也就是要找的组合数的位置。

a[1]尝试范围5——3
a[2]尝试范围4——2
a[3]尝试范围3——1
且有这样的规律:“后一个元素至少比前一个数小1”,ri+a[ri]均为4。
归纳为一般情况:
a[1]尝试范围n——r,a[2]尝试范围n-1——r-1,……,
a[r]尝试范围n-1+1——1.
由此,搜索过程中的约束条件为ri+a[ri]>=r+1,若ri+a[ri]<r就要回溯到元素a[ri-1]搜索,特别地a[r]=1时,回溯到元素a[r-1]搜索。
下面证明一下为什么是ri+a[ri]>=r+1
a[1]的最小值是r
a[2]的最小值是r-1
a[3]的最小值是r-2
a[4]的最小值是r-3

a[ri]的最小值是r-ri+1

a[r]的最小值是1
也就是说我们要设计的限制条件呢就是搜索到a[ri]的最小值之后就要回溯了。
即是a[ri]>=r-ri+1.
下面贴一下代码(在老师给的基础上改的)如有错误请指正!!!

#include<stdio.h>

void combination(int n,int r,int a[]); 
int main()
	{
		int n,r; 
		int a[20];//数组的大小会限制n的值
		n=4;
		r=3;
		a[0]=r;
		combination(n,r,a);
	}
void combination(int n,int r,int a[])
	{
		int i,ri;     
		ri=1;//数组下标索引    
		a[1]=n;//没有用数组的第一个元素
		while(a[1]!=r-1)
		{
			if (ri!=r)              //没有搜索到底
			{
				if (a[ri]>=r-ri+1)//向前搜索下一个数组元素
				{
					a[ri+1]=a[ri]-1;
					ri=ri+1;
				}
				else  //回溯上一个数组元素
				{
					ri=ri-1;  
					a[ri]=a[ri]-1;
				}  
			}
			else
			{
				for(int j=1;j<=r;j++)  
				{
					printf("%d\t",a[j]);
				}
				
				printf("\n");				
				if (a[r]==1)//每次输出之后检查是否搜索完了
				{
					ri=ri-1;
					a[ri]=a[ri]-1;
				}    //回溯
				else//没有搜索完就减一  
				{
					a[ri]=a[ri]-1;     //搜索到下一个数
				}
			}
		}
	}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值