求组合数: 求n个数(1....n)中k个数的组合

从网上down的例子,来自于:http://www.dayi.net/CExcellent/39108.asp,不得不说,递归真是没学好。弄了半天,终于给弄明白了,程序的意思。下面就分析下:

m表示,当前已经挑的个数。初始为0.

n表示当前挑的值可从n开始。

k表示要挑选的个数,程序一开始就确定的。那么k-m表示,还有几个没有挑。因为程序是从1...n,开始的。k-m的值也可以表示,挑的值的下限。如从1...5之间挑选 k=3,m=1,这表示,第一位已经挑选过,第二位最小是2,因为要保留一个1,给最后一位。

关于递归的分析,最好可以画个图。

#include
#include
#include
void combination(int n, int m);
int k,*a;
void main()
{
    int n;
    printf("Input n and k: ");
    scanf("%d%d",&n,&k);
    a=(int*)malloc(sizeof(int)*k);
    combination(n,0);
 system("pause");
}
void combination(int n,int m)
{
    int i;
    if(m     {
        for(i=n;i>=k-m;i--)  //首先这个for循环很重要,再次,k-m的控制是很合理的。
        {
            a[m]=i;
            combination(i-1,m+1);
        }
    }
    else
    {
        for(i=0;i             printf("%d ",a[i]);
        printf("\n");
    }
}

 

 

在论坛里看到的一种解法:似乎更加容易理解些,但是,是有问题的。就是对于一些下限的处理,如第一个数5,第二个数是1,那么第三个数怎么取呢?根据程序,可以知道,当第三个数<1时,本次递归就结束了。不输出而已,也是可以的,但感觉不如在程序中加入了判断,更觉得程序完整。程序如下:


#include
#include
#include
#include
#include

using namespace std;

deque result;

void solve(int n, int k) {
    if(result.size() < k) {
        for(int m = n; m >= 1; --m) {
            result.push_back(m);
            solve(m - 1, k);
            result.pop_back();
        }
    } else {
        copy(result.begin(), result.end(), ostream_iterator(cout));
        cout << endl;
    }
}

int main(int argc, char *argv[]) {
    int n, k;
    scanf("%d%d", &n, &k);
    solve(n, k);
    return 0;
}

 

你可能感兴趣的:(c/c++)