题目链接:
http://acm.nyist.net/JudgeOnline/problem.php?pid=32
描述
找出从自然数1、2、… 、n(0 < n < 10)中任取r(0<r≤n)个数的所有组合。
输入
输入n、r。
输出
按特定顺序输出所有组合。
特定顺序:每一个组合中的值从大到小排列,组合之间按逆字典序排列。
样例输入
5 3 |
样例输出
543 542 541 532 531 521 432 431 421 321 |
算法思想:
这个题目经典组合生成算法,经典组合生成算法如下图所示:
这道题所要求的是对输出进行简单的修改,将从小到大输出改为从大到小输出。所以,算法也需要做相应的修改。
首先,a[0…r]赋初值(最大值),并输出;
然后从右往左扫描a[0…r],查找第一个大于r - i的数,如果存在这样的数a[k],则将a[k]- -,并更新a[k]右边的数,a[j] = a[j - 1] + 1,j = k + 1,k + 2,…r。输出组合。
如果不存在,则说明组合已经完全生成,达到了最小值。
源代码
#include <iostream>
using namespace std;
void assemble(int n, int r)
{
int *a = new int[r];
for (int i = 0; i < r; i++)
{
//赋值最大值,即初值
a[i] = n - i;
cout << a[i];
}
cout << endl;
for (int i = r - 1; i >= 0; i--)
{
//cout << "i = " << i << "," << "a[i] = " << a[i] << "," << "r = " << r << endl;
//从右往左扫描查找大于r - i的数,如果存在,则将其a[i]--,并更新a[i]后的数
if (a[i] > r - i)
{
a[i]--;
for (int j = i + 1; j < r; j++)
{
a[j] = a[i] - j + i;
}
for (int i = 0; i < r; i++)
{
cout << a[i];
}
cout << endl;
//回溯
i = r;
}
}
}
int main()
{
int n, r;
cin >> n >> r;
assemble(n,r);
return 0;
}