写组合数:从{1,2,3,4,5}中选3个数,输出所有组合。然后扩展到从n个数中选m个数。
1、动态规划——递归
我们只需从5个数当中任选一个,然后再在剩下的4个元素中选两个;如果在剩下的4个元素中选一个,则最后再再剩下三个元素中选两个。
具体过程:
a、我们从5个元素中任选一个,然后与第0位交换;
b、我们从剩下的4个元素中任选一个,然后与第1位交换;
c、在最后的3个元素中任选一个,输出这三个元素,结束。
注意:记得还原数组,否则出错。
上程序:
#include <iostream>
void getGroup(int array[], const int size, int numSelected, const int sum);
int main(int argc, const char * argv[]) {
// insert code here...
std::cout << "Hello, World!\n";
int array[] = {1,2,3,4,5};
getGroup(array, 5, 0, 3);
return 0;
}
void getGroup(int array[], const int size, int numSelected, const int sum)
{
if (numSelected == sum)
{
for (int i=0; i<sum; ++i)
{
std::cout<<array[i]<<' ';
}
std::cout<<std::endl;
return;
}
for (int i=numSelected; i<size; ++i)
{
std::swap(array[numSelected], array[i]);
getGroup(array, size, numSelected+1, sum);
std::swap(array[i], array[numSelected]);
}
}
结果:
1 2 3
1 2 4
1 2 5
1 3 2
1 3 4
1 3 5
1 4 3
1 4 2
1 4 5
1 5 3
1 5 4
1 5 2
2 1 3
2 1 4
2 1 5
2 3 1
2 3 4
2 3 5
2 4 3
2 4 1
2 4 5
2 5 3
2 5 4
2 5 1
3 2 1
3 2 4
3 2 5
3 1 2
3 1 4
3 1 5
3 4 1
3 4 2
3 4 5
3 5 1
3 5 4
3 5 2
4 2 3
4 2 1
4 2 5
4 3 2
4 3 1
4 3 5
4 1 3
4 1 2
4 1 5
4 5 3
4 5 1
4 5 2
5 2 3
5 2 4
5 2 1
5 3 2
5 3 4
5 3 1
5 4 3
5 4 2
5 4 1
5 1 3
5 1 4
5 1 2
如果只是就组合,不要求顺序的话,如下程序:
#include <iostream>
void getGroup(int array[], const int size, int pos, int numSelected, const int sum);
int outArray[3]={0};
int main(int argc, const char * argv[]) {
// insert code here...
std::cout << "Hello, World!\n";
int array[] = {1,2,3,4,5};
getGroup(array, 5, 0, 0, 3);
return 0;
}
void getGroup(int array[], const int size, int pos, int numSelected, const int sum)
{
if (numSelected == sum)
{
for (int i=0; i<sum; ++i)
{
std::cout<<outArray[i]<<' ';
}
std::cout<<std::endl;
return;
}
for (int i=pos; i<size; ++i)
{
outArray[numSelected] = array[i];
getGroup(array, size,i+1, numSelected+1, sum);
}
}
结果:
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
2、非递归
对于固定个数的情况,非递归还是挺简单的。具体过程如下:
a、执行3次循环,每次选择一个数
b、比较这三个数,如果下标各不同,则输出。
上程序:
#include <iostream>
void getGroup(int array[], const int size);
int main(int argc, const char * argv[]) {
// insert code here...
std::cout << "Hello, World!\n";
int array[] = {1,2,3,4,5};
getGroup(array, 5);
return 0;
}
void getGroup(int array[], const int size)
{
for (int i=0; i<size; ++i)
for (int j=0; j<size; ++j)
for (int k=0; k<size; ++k)
{
if (i!=j && i!=k && j!=k)
{
std::cout<<array[i]<<' '<<array[j]<<' '<<array[k]<<std::endl;
}
}
}
如果只是就组合,不要求顺序的话,如下程序:
#include <iostream>
void getGroup(int array[], const int size);
int main(int argc, const char * argv[]) {
// insert code here...
std::cout << "Hello, World!\n";
int array[] = {1,2,3,4,5};
getGroup(array, 5);
return 0;
}
void getGroup(int array[], const int size)
{
for (int i=0; i<size-2; ++i)
for (int j=i+1; j<size-1; ++j)
for (int k=j+1; k<size; ++k)
{
if (i!=j && i!=k && j!=k)
{
std::cout<<array[i]<<' '<<array[j]<<' '<<array[k]<<std::endl;
}
}
}
结果:
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
3、二进制组合
如果只是求组合,不要求顺序的话,那么我们可以考虑二进制组合。
5选3,
00000——11111
一共是2^5=32种,选择有三个1的便是所求。
如11100就是123;10110就是134。
如何确定是1还是2还是5呢?
假设BinaryArray是00000到11111。我们设firstIndex = 0x01 & BinaryArray,如果firstIndex等于1说明选择了1,若为0说明没有选择;其他也是如此,如3,我们社thirdIndex = 0x07(0000 0100) & BinaryArray,如果thirdIndex等于1说明选择了3,若为0说明没有选择。
比较简单,不再赘述。
延伸:扩展到从n个数中选m个数呢?
如果用递归的话比较容易解决,换一下参数就行了。
不用递归的话可以考虑用二进制组合的方法。
如果这两种方法都不用,是否还用其他方法呢?