• 全部
  • 问答

高手帮忙!求组合算法问题,n个自然数中取k个的所有组合的算法。

crazylinuxer 2009-10-15 11:57:46
编写算法输出从n个自然数中取k个(k<=n)的所有组合的算法,如,当n=5,k=3时,你的算法应该输出:543,542,541,532,531,521,432,431,421,321.
...全文
1023 点赞 收藏 37
写回复
37 条回复
切换为时间正序
当前发帖距今超过3年,不再开放新的回复
发表回复
liuzhengxi2010 2011-05-22
[Quote=引用 35 楼 jjlonline 的回复:]

使用位图吧
如题目:n=5.k=3
举个例子:
1 初始化 bMask=00111b ===321
2 循环移位 bMask 01011b ===421
bMask 10011b ===521
bMask 10101b ===531
bMask 10110b ===532
bMask ......……
[/Quote]

经典啊
回复
hh_xj 2009-11-02
递归的,深度优先。
char items[5] = {'a', 'b', 'c', 'd', 'e'};
int slt(char *selected, int i, int s, int n, int k)
{
if (k == 0) {
cout << selected << endl;
return 0;
}

for (int j = s+1; j != n - k + 1 ; j++) {
selected[i] = items[j];
slt(selected, i+1, j, n, k - 1);
}
}

int main()
{
char selected[4];
selected[3] = '\0';
slt(selected, 0, -1, 5, 3);
}
回复
jjlonline 2009-11-01
使用位图吧
如题目:n=5.k=3
举个例子:
1 初始化 bMask=00111b ===321
2 循环移位 bMask 01011b ===421
bMask 10011b ===521
bMask 10101b ===531
bMask 10110b ===532
bMask .......
bMask 11100b ===543
3 这样就得到结果了,n和k是可以在初始化是设置。n就是bMask的比特个数,k就是bMask中1的个数,
回复
zztchen 2009-10-31
[Quote=引用 31 楼 northwolves 的回复:]
以前写过一个,供参考:http://blog.csdn.net/northwolves/archive/2008/11/10/3270288.aspx
[/Quote]

稍作修改,可以完美解决

#include <stdio.h>

int pop(int *);
int push(int );
void combination(int ,int );

int stack[100]={0};
int top=-1;

int n,k;

void main()
{
printf("Input two numbers:\n");
while( (2!=scanf("%d%*c%d",&n,&k)) )
{
fflush(stdin);
printf("Input error! Again:\n");
}
combination(n,k);
printf("\n");
}

void combination(int m,int n)
{
int temp=m;
push(temp);
while(1)
{
if(1==temp)
{
//当出栈后栈空&&栈底元素为可能取的最小值时退出
if(pop(&temp)&&stack[0]==n)
{
break;
}
}
else if( push(--temp))
{
for (int c = 0; c < k; c++)
{
printf("%d", stack[c]);
}
printf(" ");
//输出后栈顶元素出栈
pop(&temp);
}
}
}
//入栈函数
int push(int i)
{
stack[++top]=i;
if(top < (k-1))
{
return 0; //返回0表示堆栈不满
}
else
{
return 1; //返回1表示堆栈满
}
}
//出栈函数
int pop(int *i)
{
*i=stack[top--];
if(top>=0)
{
return 0;//返回0表示堆栈空
}
else
{
return 1;//返回0表示堆栈不空
}
}
回复
crazylinuxer 2009-10-23
[Quote=引用 31 楼 northwolves 的回复:]
以前写过一个,供参考:http://blog.csdn.net/northwolves/archive/2008/11/10/3270288.aspx
[/Quote]
老大!你的博客不错!
回复
pangjingji 2009-10-22
#include<iostream>
using namespace std;
int get_combination(int a[],int n,int k);
int main()
{
int a[10]={0,1,2,3,4,5,6,7,8,9};
int counter=get_combination(a,10,3);
cout<<counter;
cout<<endl;
return 0;
}
int get_combination(int a[],int n,int k)
{
int count=0;
int *m = new int[k];
for(int i=0;i<k;i++)
m[i]=i;
for(int i=0;i<k;i++)
cout<<m[i];
cout<<endl;
count++;
for(int i=k-1;i>=0;i--)
{

if(m[i]<n-k+i)
{
{
//cout<<i<<" "<<"i"<<endl;
m[i]=m[i]+1;
for(;i<k-1;i++)
m[i+1]=m[i]+1;
//cout<<m[k-1]<<endl;

}
for(i=0;i<k;i++)
cout<<m[i];
cout<<endl;
count++;

}
else continue;
}
delete []m;
return count;
}
回复
northwolves 2009-10-22
elated 2009-10-21
[Quote=引用 25 楼 crazylinuxer 的回复:]
引用 24 楼 elated 的回复:
C/C++ code
#include <stdio.h>#define N 50int a[N];int AllCombinations(int*a,int n ,int t)
{int j=0;
    a[t]= n;
    a[t+1]=0;for (int i=0; i < t; i++)
    {
        a[i]= i;
    }do
    {int i;
      ¡­

老大啊,给点注释嘛,看不懂。
[/Quote]
我也说不太明白,只知道这样做
我也是现看书写的
具体算法描述参看《计算机程序设计艺术》第4卷,第3册7.2.1.3节,讲的很清楚
《组合数学》上也有讲到这个算法
回复
feiyangdn 2009-10-20
少了a[k] = n
void PrintComb(int n, int k)
{
int a[100];
int i = 0,j = 0;
for (i=0;i<=k;i++)a[i]=i;
a[k]=n;
while (1)
{
for (i=0;i<k;i++)printf("%d",n-a[i]);printf("\t");
for (i=k-1;a[i+1]-a[i]<2;i--)if(i==0)return;
for (a[i]++;i<k-1;i++)a[i+1]=a[i]+1;
}
}
回复
feiyangdn 2009-10-20
用进位的方法处理
void PrintComb(int n, int k)
{
int a[100];
int i = 0,j = 0;
for (i=0;i<=k;i++)a[i]=i;
while (1)
{
for (i=0;i<k;i++)printf("%d",n-a[i]);printf("\t");
for (i=k-1;a[i+1]-a[i]<2;i--)if(i==0)return;
for (a[i]++;i<k-1;i++)a[i+1]=a[i]+1;
}
}
回复
crazylinuxer 2009-10-20
[Quote=引用 24 楼 elated 的回复:]
C/C++ code
#include<stdio.h>#define N 50int a[N];int AllCombinations(int*a,int n ,int t)
{int j=0;
a[t]= n;
a[t+1]=0;for (int i=0; i< t; i++)
{
a[i]= i;
}do
{int i;
¡­
[/Quote]
老大啊,给点注释嘛,看不懂。
回复
zhengjiankang 2009-10-20
不好意思我之前没看懂题意,下面我又写了一个函数

主要思想就是以前学组合数的时候,n个里面选k个的时候。我选上一个,然后在后面的n-1个里面选k-1个,或者我不选这1个,在后面的n-1个里面选k个,这样的思想,用的递归函数。具体错了没有我也不是很清楚哈,没调试,就拿几个数试验了下。

下面是c++代码:

#include <iostream>

#include<cstdlib>
#include <vector>
#include <string>
using namespace std;

vector<string> Select(vector<int> iVec, unsigned int k)
{
vector<string> sVec;
if(iVec.size() < k)
{
cerr << "参数非法!";
// sVec.clear();
return sVec;
}
else if(k == 0)
{
// sVec.clear();
return sVec;
}

if(k == 1)
{
sVec.clear();
vector<int>::iterator it;
for(it = iVec.begin(); it != iVec.end(); it ++)
{
char* ch = new char[12];
_itoa_s(*it, ch, 12, 10);
sVec.push_back(ch);
}
}
else if(k == iVec.size())
{
string str;
str = "";
vector<int>::iterator it;
for(it = iVec.begin(); it != iVec.end(); it ++)
{
char* ch = new char[12];
_itoa_s(*it, ch, 12, 10);
if(str.size() != 0)
str += " ";
str += ch;
}
sVec.push_back(str);
}
else
{
vector<int> iTemp;
vector<string> sTemp;
iTemp = iVec;
int temp = *iTemp.rbegin();
char* ch = new char[12];
_itoa_s(temp, ch, 12, 10);
iTemp.pop_back();
sVec = Select(iTemp, k);
sTemp = Select(iTemp, k - 1);
vector<string>::iterator it;
for(it = sTemp.begin(); it != sTemp.end(); it ++)
{
string str;
str = *it;
str += " ";
str += ch;
sVec.push_back(str);
}
}
return sVec;
}

int main()
{
vector<string> sVec;
vector<int> iVec;
int k = 3;
for(int i = 1; i < 6; i ++)
iVec.push_back(i);
sVec = Select(iVec, k);

vector<string>::iterator it;
for(it = sVec.begin(); it != sVec.end(); it ++)
cout << *it << '\t';
cout << endl;

return 0;
}
回复
pangjingji 2009-10-20
[Quote=引用 24 楼 elated 的回复:]
C/C++ code
#include<stdio.h>#define N 50int a[N];int AllCombinations(int*a,int n ,int t)
{int j=0;
a[t]= n;
a[t+1]=0;for (int i=0; i< t; i++)
{
a[i]= i;
}do
{int i;
¡­
[/Quote]思想挺好
回复
elated 2009-10-19

#include <stdio.h>
#define N 50

int a[N];

int AllCombinations(int *a, int n , int t)
{
int j = 0;
a[t] = n;
a[t+1] = 0;

for (int i = 0; i < t; i++)
{
a[i] = i;
}

do
{
int i;
j++;
for (i = t-1 ; i>=0 ; i--)
{
printf ("%d ", a[i]);
}
printf ("\n");

i = 0;
while ( a[i] + 1 == a[i+1] )
{
a[i] = i;
i++;
}
if ( i >= t)
break;
a[i]++;
continue;
}
while (1);

return j;
}


int main()
{
printf ( "T : %i\n", AllCombinations (a, 10, 5 ) );
}
回复
crazylinuxer 2009-10-17
还是不明白。
回复
whywen_MoJian 2009-10-17
mark
回复
crazylinuxer 2009-10-17
[Quote=引用 22 楼 wwwwwwking 的回复:]
#include <new>
#include <iostream>
using namespace std;

int tmp[10] = {1,2,3,4,5,6,7,8,9};
int out[10];

// select k elements from n elements
void get_combo(int n, int k, int layer, int e)
{
if (layer == k+1)
{
for (int i = 0; i < k; ++i)
cout < < out[i];
cout < < endl;
return ;
}
for (int j = e-1; j >= k-layer; --j)
{
out[layer-1] = tmp[j];
get_combo(n, k, layer+1, j);
}
}

int main()
{
get_combo(5,3,1,5);
return 0;
}

就这个吧。呵呵
[/Quote]
Thank you sir ~
回复
booksoon 2009-10-17
NP问题啊~~~
回复
wwwwwwking 2009-10-17
#include <new>
#include <iostream>
using namespace std;

int tmp[10] = {1,2,3,4,5,6,7,8,9};
int out[10];

// select k elements from n elements
void get_combo(int n, int k, int layer, int e)
{
if (layer == k+1)
{
for (int i = 0; i < k; ++i)
cout << out[i];
cout << endl;
return ;
}
for (int j = e-1; j >= k-layer; --j)
{
out[layer-1] = tmp[j];
get_combo(n, k, layer+1, j);
}
}

int main()
{
get_combo(5,3,1,5);
return 0;
}

就这个吧。呵呵
回复
h20090304001 2009-10-17
void Choice(int k, int n, List S)
{
if(k==0) Print(S);
S.AddTail(n);
Choice(k-1, n-1, S);
S.RemoveTail();
Choice(k, n-1, S);
}

调用:
List S={};
Choice(k, n, S);

具体问题具体处理,关系到存储和计算效率,递归限制,
递归是可以通过堆栈结构解决的,
列举n选k的所有组合是低效率的,显然适合n不大的情况,
另一组合问题是此问题的计数问题: C(k,n)
当n固定,对不同的k需要反复计算时可以一次性计算各C(k,n)并存储,
充分利用这些值的共享数据。
回复
加载更多回复
相关推荐
发帖
数据结构与算法
创建于2007-08-27

3.2w+

社区成员

数据结构与算法相关内容讨论专区
申请成为版主
帖子事件
创建了帖子
2009-10-15 11:57
社区公告
暂无公告