数组(1,3,4,7,8),选取5个数的所有组合

helanshan 2009-06-22 01:03:02
参考了些算法,总是不得要领,高分,求完整代码。。
...全文
484 20 打赏 收藏 转发到动态 举报
写回复
用AI写文章
20 条回复
切换为时间正序
请发表友善的回复…
发表回复
小亮 2010-07-12
  • 打赏
  • 举报
回复
期待通用的算法
helanshan 2009-06-22
  • 打赏
  • 举报
回复
to楼上:是组合,不是排列
  • 打赏
  • 举报
回复
就是全排列啊。

给你个递归全排列吧。不过是字符串的,无所谓,只要改输入数据而已。


#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>

void swap(char *str1,char *str2)
{
char temp;
temp=*str1;
*str1=*str2;
*str2=temp;
}

void permStr(char *str,int i)
{
//printf("%d",i);
if(i==strlen(str)-1)
printf("%s\n",str);
else
{
for(int j=i;j<strlen(str);j++)
{
//printf("i %d,j %d",i,j);
swap(&str[i],&str[j]);
permStr(str,i+1);
swap(&str[i],&str[j]);
}
}
}

void main()
{
char str[]={"abcde"};

permStr(str,0);

}



goodname 2009-06-22
  • 打赏
  • 举报
回复


#include <time.h>
#include <iostream>
#include <iomanip>
using namespace std;

# define MAXN 100
int a[MAXN]; //定位数组,用于指示选取元素集合数组的位置,选取元素集合数组0 起始
void comb(int m,int r)
{
int cur;//指示定位数组中哪个成员正在移进

unsigned int count=0;

//初始化定位数组,0 起始的位置 ,开始的选择必是位置 0,1,2
for(int i=0;i<r;i++)
a[i]=i;

cur=r-1;//当前是最后一个成员要移进

do{
if (a[cur]-cur<=m-r ){

count++;

for (int j=0;j<r;j++)
cout<<setw(4)<<a[j];
cout<<endl;

a[cur]++;

continue;
}
else{
if (cur==0){
cout<<count<<endl;
break;
}

a[--cur]++;
for(int i=1;i<r-cur;i++){
a[cur+i]=a[cur]+i;
}

if(a[cur]-cur<m-r)
cur=r-1;
}
}while (1);
}

void printtime(void) //打印当前时间的函数
{
char tmpbuf[128];
time_t ltime;
struct tm *today;

time(<ime);
today = localtime(<ime );
strftime(tmpbuf,128,"%Y-%m-%d %H:%M:%S",today);
cout<<tmpbuf<<endl;
}

int main (int argc, char *argv[])
{

int m,r;
cout<<"m"<<endl;
cin>>m;
cout<<"r"<<endl;
cin>>r;
printtime();
comb(m,r);
printtime();
return(0);
}



其他解法参考
http://hi.baidu.com/jackmawt/blog/item/0cf1148a7c7dc3779f2fb4c3.html
jest850615 2009-06-22
  • 打赏
  • 举报
回复
12楼求排列的不对吧?
6取5的排列是 6!=720
liao05050075 2009-06-22
  • 打赏
  • 举报
回复
枚举所有组合情况,然后去掉不符合的组合就行了。

#include<stdio.h>

int main()
{
int num[20];
int n,m,tmp;
int i,j,k;
scanf("%d%d",&n,&m);
for(i=0;i<n;i++)scanf("%d",&num[i]);

for(i=0;i<(1<<n);i++)//枚举所有组合情况
{
k=i;
tmp=0;
while(k)//计算它选中了几个数,不是选中m个的就不输出
{
if(k&1) tmp++;
k>>=1;
}
if(tmp!=m) continue;
k=i;
for(j=0;j<n;j++)//测试某一位是否为1,为1则表示它已选中
{
if(k&1) printf("%d ",num[j]);
k>>=1;
}
puts("");
}
return 0;
}
先输入n m表示n个中选 m个
然后输入n个数
lingyin55 2009-06-22
  • 打赏
  • 举报
回复
不知道为啥用不了代码格式化的功能,比较乱,楼主将就着看吧。

[Quote=引用 12 楼 lingyin55 的回复:]
#include <stdio.h>
#include <iostream>
using namespace std;

void func(int n,int *a);

void main()
{
int arr[]={1,3,4,6,7,8};
func(5,arr);
}

//求n个数的全排列
//
void func(int n,int *a)
{
static int Num = 0;
int *i = new int[n];
int c=0,j;
i[c]=-1;
while(i[0] <n)
{
if(++i[c] <n)
{
for(j=0; j <c; j++)
if( i[j] == i[c] )
break; …
[/Quote]
jest850615 2009-06-22
  • 打赏
  • 举报
回复
恐怕得用递归
lingyin55 2009-06-22
  • 打赏
  • 举报
回复
#include <stdio.h>
#include <iostream>
using namespace std;

void func(int n,int *a);

void main()
{
int arr[]={1,3,4,6,7,8};
func(5,arr);
}

//求n个数的全排列
//
void func(int n,int *a)
{
static int Num = 0;
int *i = new int[n];
int c=0,j;
i[c]=-1;
while(i[0]<n)
{
if(++i[c]<n)
{
for(j=0; j<c; j++)
if( i[j] == i[c] )
break;

if(j==c)
{
if(c+1<n)
{
++c;
i[c]=-1;
// continue;
}
else
{
cout.width(2);
cout<<Num++<< " ";
for(int j=0;j<n;j++)
cout<<a[i[j]]<<",";
cout<<endl;
}
}
}
else
c--;
}
}
jest850615 2009-06-22
  • 打赏
  • 举报
回复
缺几个就加几个循环。够暴力吧。。。
helanshan 2009-06-22
  • 打赏
  • 举报
回复
7楼的算法很精妙,但缺少通用性,如果是9选5或9选7的组合??
关于加分,可以重开贴送出。。
pathuang68 2009-06-22
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 liao05050075 的回复:]
6选5的组合只有6种。你就从中选一个不要的数就是了。

C/C++ code
#include<stdio.h>

int main()
{
int num[6]={1,3,4,6,7,8};
int i,j,tmp;
for(i=0;i<6;i++)
{
for(j=0;j<6;j++)
if(j!=i) printf("%d",num[j]);
puts("");
}
return 0;
}
[/Quote]
精妙
光宇广贞 2009-06-22
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 liao05050075 的回复:]
6选5的组合只有6种。你就从中选一个不要的数就是了。

C/C++ code
#include<stdio.h>

int main()
{
int num[6]={1,3,4,6,7,8};
int i,j,tmp;
for(i=0;i<6;i++)
{
for(j=0;j<6;j++)
if(j!=i) printf("%d",num[j]);
puts("");
}
return 0;
}
[/Quote]

还是此法精妙,哈哈。好。
liao05050075 2009-06-22
  • 打赏
  • 举报
回复
6选5的组合只有6种。你就从中选一个不要的数就是了。

#include<stdio.h>

int main()
{
int num[6]={1,3,4,6,7,8};
int i,j,tmp;
for(i=0;i<6;i++)
{
for(j=0;j<6;j++)
if(j!=i) printf("%d",num[j]);
puts("");
}
return 0;
}

光宇广贞 2009-06-22
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 helanshan 的回复:]
不好意思,题目错了,是(1,3,4,6,7,8),6选5的组合。。解决后再加50分。。
[/Quote]

你怎么加这五十分?
helanshan 2009-06-22
  • 打赏
  • 举报
回复
不好意思,题目错了,是(1,3,4,6,7,8),6选5的组合。。解决后再加50分。。
光宇广贞 2009-06-22
  • 打赏
  • 举报
回复
而所有组合的情况,有一个数学等式, ( 1 + 1 ) ^ n = Sum ( C ( n, m ), {m = 0 : n} ),就是所有N选M的组合数的总和,结果是 2^n 之多,而这个 2^n 恰好又是N位全零到全一的变化过程。依这个思路做就可以了。
lingyin55 2009-06-22
  • 打赏
  • 举报
回复
#include <iostream>
/*10个数,取5个,打印出所有可能的组合,假设不考虑重复数字*/

const int L=10; //10个数字

const int C=5;//选5个

int *x;
/*偏移数组,后一个数相对于前一个数偏移的距离,至少为1
比如1,2,3选两个数
可能的情况 对应的x数组
1 2 0 1
1 3 0 2
2 3 1 1
*/
bool place(int k){//判断第k步,是否超界,所有的偏移距离之和要小于坐标上限L-1

int sum = 0;
for(int i = 0;i <= k; i++)
sum += x[i];
if(sum >= L)
return false;
else return true;
}
int main(){
x = new int[C];
int sum = 0;//总共的组合结果

int k=0;//步数

x[k] = -1;
int a[L];//待选数

for(int i=0;i<L;i++){//初始化

a[i]=rand()%100;
printf("%d ", a[i]);
}
printf("\n");
while(k >= 0){//如果回溯到-1步,说明回溯结束

x[k]++;//第k步偏移加1

if(place(k)){//如果没有超界

if(k == C-1){//如果已经选出了C个数,则打印,统计结果

int t = 0;
for(int i = 0;i < C;i++){
t += x[i];
printf("%d ", a[t]);
}
printf("\n");
sum++;
}
else{//否则,则尝试下一步

k++;
x[k 000cc">] = 0;
}
}else//如果超界了,退回上一步

k--;
}
printf("总共组合数目%d\n", sum);
delete []x;
}

文章出处:http://www.diybl.com/course/3_program/c++/cppsl/20081117/151296_2.html
liao05050075 2009-06-22
  • 打赏
  • 举报
回复
所有组合的话,使用位的0或1来表示某个数是不是选中,因为从00000到11111的变化过程中,恰好所有组合情况都出现了。
这样程序是十分简单的。

#include<stdio.h>

int main()
{
int num[5]={1,3,4,7,8};
int i,j,k;
for(i=0;i<=31;i++)//枚举所有组合情况
{
k=i;
for(j=0;j<5;j++)//测试某一位是否为1,为1则表示它已选中
{
if(k&1) printf("%d ",num[j]);
k>>=1;
}
puts("");
}
return 0;
}
光宇广贞 2009-06-22
  • 打赏
  • 举报
回复
所有组合还是排列?

如果是排列的话,用 <algorithm> 中的
next_permutation 与 prev_permutation 可实现全排列
使用 next_permutation 时,需要先将数组的元素顺序
使用 prev_permutation 时,需要先将数组的元素逆序。

64,632

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧