算法设计与分析:第五章 回溯法 5.6找n个数中r个数的组合

/*
找n个数中r个数的组合
例如:当 n=5, r=3 时 , 所有组合为:
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 total=10 { 组合数 }

分析1:
每组3个数的特点:
1)互不相同;
2)前面的数小于后面的数;
将上述两条作为约束条件。
3) 当 r =3时,可用三重循环对
每组中的3个数进行 枚举 。

用递归法设计该问题:
每个组合中的数据必须从大到小排列,因为递归算法设计是要找出大规模问题域
小规模问题之间的关系

分析2:
分析n=5,r=3时10个组合数
1)首先固定第一个数5,然后就是n=4,r=2的组合数,共6个组合
2)其次固定第一个数4,其后就是n=3,r=2的组合数,共3个
3)最够固定第一个数3,后面就是n=2,r=2的组合数,共1个
至此,找到了“5个数中3个数的组合”与"4个数中2个数的组合"
,3个数中2个数的组合,2个数中2个数的组合的递归关系


递归算法的三个步骤:
1)n个数中r各数组合递推到n-1个数r-1个数有组合,n-2个书中r-1个数有组合
,...,r-1个数中有r-1个数有组合,共n-(r-1)次递归
2)递归地边界条件是r=1
3)函数主要操作是输出,每当低轨道r=1时,就有一个新的组合产生,输出他们和
一个换行符,
先固定5,然后进行多次递归,数字5要多次输出,所以要用数组存储以备每次
递归到r=l时输出。
同样每次向下递归都要用到数组,所以将数组设置为全局变量

输入:
5 3
输出:
10
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

*/

#include 
#include 

using namespace std;

const int MAXSIZE = 100;
int g_iArr[MAXSIZE];

bool isOk()
{
	int iTemp;
	int iNext;
	int iCur = 100000;
	for(int j = g_iArr[0]; j >= 1; j--)
	{
		iNext = g_iArr[j];//第一个数
		//判断前面的数是否比自己大,正常的顺序应该是前面大,后面小,如果不符合就是前面<=后面。现在拿到的第一个是最前面的
		if( iCur <= iNext)
		{
			return false;
		}		
		iCur = iNext;
	}
	return true;
}

void dfs(int n,int r)
{
	for(int i = n ; i >= r ; i--)
	{
		//设定当前选中的元素为第一个,因为元素的选取是从大到小,因此为i
		g_iArr[r] = i;
		//递归基,当r减为1,说明成功了
		if(r == 1)
		{
			if(isOk())
			{
				for(int j = g_iArr[0]; j >= 1; j--)
				{
					cout << g_iArr[j];
				}
				cout << endl;
			}
		}
		//递归步,从剩余n-1个数中挑选r-1个数
		else
		{
			//添加限制条件,后面的大于前面,不能重复
			dfs(n-1,r-1);
		}
	}
}

void process()
{
	int n,r;
	while(EOF != scanf("%d %d",&n,&r))
	{
		//要设置初始值,为什么为r,g_iArr[r] = 就等于最大值了
		g_iArr[0] = r;
		dfs(n,r);
	}
}

int main(int argc,char* argv[])
{
	process();
	getchar();
	return 0;
}

你可能感兴趣的:(算法设计与分析)