P1157
题目描述
排列与组合是常用的数学方法,其中组合就是从 nn 个元素中抽出 rr 个元素(不分顺序且 r \le n)r≤n) ,我们可以简单地将 nn 个元素理解为自然数 1,2,…,n1,2,…,n ,从中任取 rr 个数。
现要求你不用递归的方法输出所有组合。
例如 n=5,r=3n=5,r=3 ,所有组合为:
12 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 5123,124,125,134,135,145,234,235,245,345
输入输出格式
输入格式:
一行两个自然数
。
输出格式:
所有的组合,每一个组合占一行且其中的元素按由小到大的顺序排列,每个元素占三个字符的位置,所有的组合也按字典顺序。
注意哦!输出时,每个数字需要 33 个场宽,pascal可以这样:
输入输出样例
输入样例#1:
5 3
输出样例#1:
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
思路
因为n的大小只有21,那我们可以用二进制上的每一位来代表每一个数,那么只用从0枚举到 即可然后对每个数进行&操作,若1的个数等于r的把这个数加到结构体中,因为然后还要对结构体进行按照字典序从小到大排序即可
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <algorithm>
#include <math.h>
using namespace std;
struct node
{
int v[21];
}a[3000000];
int n,r;
bool cmp(node a,node b)
{
for(int i=0;i<r;i++)
if(a.v[i]!=b.v[i])
return a.v[i]<b.v[i];
}
int main()
{
scanf("%d%d",&n,&r);
int num=0;
for(int i=0;i<(1<<n);i++)
{
int cnt=0;
for(int j=0;j<21;j++)
if(i&(1<<j))
cnt++;
if(cnt==r)
{
int k=0;
for(int j=0;j<21;j++)
if(i&(1<<j))
{
a[num].v[k++]=j+1;
}
num++;
}
}
sort(a,a+num,cmp);
for(int i=0;i<num;i++)
{
for(int j=0;j<r;j++)
printf("%3d",a[i].v[j]);
cout<<endl;
}
return 0;
}