排列组合专题

1 排列

1.1 参考

(1)C语言如何打印一个数组排列组合?https://segmentfault.com/a/1190000000725176

1.2 思路

n个元素选择m个进行排列

数组arr,长度为n,找出从中取出m个数的所有组合。例如,{1,2,3}中选2个全排列如下:{1,2},{1,3},{2,1},{2,3},{3,1},{3,2}。假设数组的元素没有重复,取出的m个数也没有重复。
参考1中提供了思路如下:

1.把第1个数换到最前面来(本来就在最前面),准备打印1xxx,再对剩下的数做全排列。
2.把第2个数换到最前面来,准备打印2xxx,再对剩下的数排列。
……
3.把第n个数换到最前面来,准备打印3xxx,再对剩下的数做全排列。

注意:由此可见按顺序将数组中的1个数交换到最前面的位置,然后递归解决,把对整个序列做全排列的问题归结为对它的子序列做全排列的问题。递归边界是已经排列到m个元素。

1.3 c++实现

#include <iostream>
#include <algorithm>
//#include <cstdio>
using namespace std;

/**打印从n个元素的数组中选取m个的排列*/
void printAllPermutation(int arr[], int offset, int n, int m){

    // 排列到m个数时
    if(offset == m){
        // 打印
        for(int i = 0; i < m; ++i){
            cout << arr[i] << " ";
        }
        cout << endl;
    }

    for(int i = offset; i < n; ++i){
        swap(arr[i], arr[offset]);
        printAllPermutation(arr, offset+1, n, m);
        swap(arr[i], arr[offset]);
    }
}

int main()
{
    //freopen("out.txt", "w", stdout);
    int arr[]= {1,2,3,4,5,6};
    int r = 4;
    printAllPermutation(arr, 0, sizeof(arr)/sizeof(arr[0]), r);
    //fclose(stdout);
    return 0;
}

2 组合

2.1 参考

(1)POJ 1753 Flip Game (递归枚举):http://www.cnblogs.com/shuaiwhu/archive/2012/04/27/2474041.html
(2)从数组中取出r个数的所有组合:http://www.acmerblog.com/combinations-of-r-elements-6059.html
(3)从数组中取出n个元素的所有组合(递归实现)http://www.cnblogs.com/shuaiwhu/archive/2012/04/27/2473788.html

2.2 思路

n个元素选择r个进行组合

数组arr,长度为n,找出从中取出r个数的所有组合。例如:对于数组{1, 2, 3, 4} ,r = 2,则打印出:{1, 2}, {1, 3}, {1, 4}, {2, 3}, {2, 4} ,{3, 4}. 也就是 组合公式 Cnm=C24=6 个。 假设数组的元素没有重复,取出的r个数也没有重复。
参考2给出的思路是:

使用递归是比较容易解决,类似分治法。组合数有如下的递归关系:
Crn=Cr1n1+Crn1 (即对第n个物品选择/不选)我们可以考虑对当前的数取还是不取,从而不断缩小问题的范围。

2.3 c++实现

#include <iostream>

using namespace std;

/**打印在含n个元素的数组中选取r个元素所有组合,
公式:C(n, r) = C(n-1, r-1) + C(n, r-1),第n个元素选或不选
arr[] 输入数组,
data[] 保存当前的一个组合
start, end 剩余数组的起始位置
count 已选取元素的个数
r 总共要选取元素的个数
*/
void printAllCombination(int arr[], int data[], int start, int end, int count, int r)
{
    // 如果剩下的数组不够(r-count)就直接返回,表示目前选择的方案不可能
    if(start + (r - count) > end) return;

    // 组合够r个就打印,并返回
    if(count == r){

        for(int i = 0; i < r; ++i){
            cout << data[i] << " ";

        }
        cout << endl;
        return;
    }
    //挑选当前数字
    data[count] = arr[start];
    printAllCombination(arr, data, start+1, end, count+1, r);
    //不挑选当前数字
    printAllCombination(arr, data, start+1, end, count, r);
}

int main()
{
    int arr[]= {1,2,3,4,5,6};
    int r = 4;
    int *data = new int[r];//保存当前的一个组合
    printAllCombination(arr, data, 0, sizeof(arr)/sizeof(arr[0]), 0, r);

    return 0;
}

附:数组去重

参考:
简单算法:去掉1维数组中的重复项:http://bbs.csdn.net/topics/70049565
看了一下该链接里的解决方案,有以下的几种方法
(1)先对数组进行排序,然后再扫描一遍相邻的已读数组删去
(2)堆排序的同时剔除重复元素,就像STL中的set类做的一样
(3)读数组、插入一棵二叉排序树中、遍历二叉排序树存到数组中。
然而我只看懂了第(1)种,第(2)种没有动手去写,第(3)种不太懂啊,所以直接上第(4)种:
(4)使用std::set, 用原始数组作为set的初始化参数,直接就可以筛去重复元素:

#include <iostream>
#include <set>
using namespace std;
int main()
{
    int arr[] = {1, 1, 2, 2, 2, 3, 4, 5, 6, 6};

    set<int> arr_set(arr, arr+sizeof(arr)/sizeof(arr[0]));

    cout <<"set size: " << arr_set.size() << endl;
    for (set<int>::const_iterator itor = arr_set.begin();
         itor != arr_set.end(); ++itor){
        cout << (*itor) << " ";
    }
    cout << endl;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值