程序最美(寻路)

你还在坚持练习你的技术吗?运动员天天训练,音乐家也会演练更难的曲章。你呢?

组合序列、排列序列的生成实现

组合序列、排列序列的生成实现

         前面我们已经讨论了关于组合数、排列数的生成《排列、组合的计算》,并没有涉及组合序列和排列序列是如何生成的。这里我们将讨论序列和排列序列是如何生成的,首先我们讨论组合序列。

一、组合序列

假如有如下集合(注意,集合中的元素是互异的):

0, 1, 2, 3, 4, 5, 6, 7, 8, 9

         我们从该集合中选取3个元素,问有多少种组合,这些组合具体是什么?

         首先,我们给出程序如下:

// 组合序列的生成
#include <iostream>
#include <vector>
using namespace std;

void comb(const vector<int>& arr, int beg, int m, vector<vector<int> >& coms, vector<int>& tmp, int& total)
{
    if (m > arr.size() - beg)
    {
        return;
    }
    if (m == 0)
    {
        coms.push_back(tmp);
        ++total;
    }
    else
    {
        tmp.push_back(arr[beg]);
        comb(arr, beg+1, m-1, coms, tmp, total);
        tmp.pop_back();
        
        comb(arr, beg+1, m, coms, tmp, total);
    }
}

int main()
{
    int a[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    vector<int> arr(a, a + sizeof (a) / sizeof (*a));
    
    vector<vector<int> > coms;
    vector<int> tmp;
    int total = 0;
    comb(arr, 0, 4, coms, tmp, total);
    
    for (vector<vector<int> >::size_type i = 0; i != coms.size(); ++i)
    {
        for (vector<int>::size_type j = 0; j != coms[i].size(); ++j)
        {
            cout << coms[i][j] << ' ';
        }
        cout << endl;
    }
    cout << coms.size() << endl;
    cout << total << endl;
    
    system("PAUSE");
    return 0;
}

 

         程序的算法是根据组合的特性而得的:C(N, M) = C(N-1, M-1) + C(N-1, M)。

         程序运行的实例为:C(10, 4) = 210,组合数也可以根据之前的程序用公式得到。

 

二、排列序列

有集合:

0, 1, 2, 3, 4, 5, 6, 7, 8, 9

         求该集合的排列。

         根据排列的性质A(N, M) = N*A(N-1, M-1)。

         我们利用这个性质用递归实现:

// 排列递归实现
#include <iostream>
#include <vector>
using namespace std;

void exchange(int& a, int& b)
{
    int t = a;
    a = b;
    b = t;
}

void
perm(
  const vector<int>& arr_
, int n
, int beg
, vector<vector<int> >& pers
, vector<int>& tmp
, int& total
)
{
    static vector<int> arr(arr_);
    if (n == 0)
    {
        pers.push_back(tmp);
        ++total;
    }
    for (int i = beg; i != arr.size(); ++i)
    {
        exchange(arr[beg], arr[i]);
        tmp.push_back(arr[beg]);
        perm(arr, n-1, beg+1, pers, tmp, total);
        tmp.pop_back();
        exchange(arr[beg], arr[i]);
    }
}

int main()
{
    int a[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    vector<int> arr(a, a + sizeof (a) / sizeof (*a));
    vector<bool> flags(arr.size(), false);
    vector<vector<int> > pers;
    vector<int> tmp;
    int total = 0;
    perm(arr, 3, 0, pers, tmp, total);
    
    for (vector<vector<int> >::size_type i = 0; i != pers.size(); ++i)
    {
        for (vector<int>::size_type j = 0; j != pers[i].size(); ++j)
        {
            cout << pers[i][j] << ' ';
        }
        cout << endl;
    }
    cout << pers.size() << endl;
    cout << total << endl;
    
    system("PAUSE");
    return 0;
}

 

         程序的实现逻辑为:根据排列公式A(n, m) = n*A(n-1, m-1),对当前位置取n个元素,然后递归计算后面的A(n-1, m-1)。所以得到以上。

         当arr为:

1, 2, 3, 4, 5, 6

         时,求其全排列为:

 

三、总结

     以上对组合序列和排列序列的生成程序进行了讨论。实质上就是根据组合的性质:

C(N, M) = C(N-1, M-1) + C(N-1, M)

以及排列的性质:

       A(N, M) = N * A(N-1, M-1)

利用递归的方式进行求解。

         由于组合公式中只是相加的方式,所以递归程序中不存在直接的循环。排列公式中存在变量N,所以在实际的实现种需要有直接的循环进行体现。

         什么时候使用递归,如何使用递归,将在下一篇种进行介绍。

         另外,关于组合、排列的程序实现,可以进行进一步的封装。我们这里没有进行进一步的封装。如果封装,有如下接口:

         组合:void comb(const vector<int>& arr, int m, vector<vector<int> >& coms, int& total);

         排列:void perm(const vector<int>& arr, int m, vector<vector<int> >& pers, int& total);

         全排列:void full_perm(const vector<int>& arr, vector<vector<int> >& pers, int& total);

posted on 2013-06-28 22:53  unixfy  阅读(869)  评论(0编辑  收藏  举报

导航