组合数
时间限制:3000 ms | 内存限制:65535 KB
难度:3
-
描述
- 找出从自然数1、2、... 、n(0<n<10)中任取r(0<r<=n)个数的所有组合。
-
输入
- 输入n、r。 输出
- 按特定顺序输出所有组合。
特定顺序:每一个组合中的值从大到小排列,组合之间按逆字典序排列。
样例输入 -
5 3
样例输出 -
543 542 541 532 531 521 432 431 421 321
题解:此题有两种解题方法<1>利用stl中的prev_permutation()函数。<2>使用dfs。
代码如下:
<1> 利用prev_permutation()函数 (降序全排列)。
#include<cstdio>
#include<algorithm>
using namespace std;
int a[15]; //存储数据
int b[15]; //比对是否是降序排列
int c[15]; //比对是否与上次输出数列一样
int n,r;
bool cmp(int x,int y){ //由大到小排序
return x>y;
}
bool Judge(){ //判断是否是降序
int num=0;
sort(b,b+r,cmp);
for(int i=0;i<r;i++){
if(a[i]==b[i]) num++;
}
return num==r;
}
bool Judge2(){ //判断本次数列是否与上次输出数列重复
int num2=0;
for(int i=0;i<r;i++){
if(c[i]==a[i]) num2++;
}
if(num2!=r) return true;
return false;
}
int main()
{
scanf("%d%d",&n,&r);
for(int i=0;i<n;i++) //赋值
a[i]=i+1;
sort(a,a+n,cmp); //首次降序排列
do{
for(int i=0;i<r;i++)
b[i]=a[i];
if(Judge()&&Judge2()){ //判断,若是降序且与先前输出数列不重复
for(int i=0;i<r;i++){
c[i]=a[i];
}
for(int i=0;i<r-1;i++)
printf("%d",a[i]);
printf("%d\n",a[r-1]);
}
}while(prev_permutation(a,a+n)); //降序对
return 0;
}
<2> DFS
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
int n, r;
int a[12];
bool visit[12]; //记录当前位置状态,看是否被遍历过
void DFS(int x,int cur){ //入口,当前层
if(cur>r) //当选的数已经足够时,结束第当前搜索,返回到上个搜索执行下一步
return ;
for(int i=x;i>=1;i--)
{
if(!visit[i]) //若未被取过值,则此值可取
{
visit[i]=true;
a[cur]=i; //记录当前层数据
if(cur==r) //达到第r层,开始输出
{
for(int i=1;i<=r;i++)
printf("%d",a[i]);
printf("\n");
}
DFS(i-1,cur+1); //进入下一层
visit[i]=false; //由于当前层已经取过,再恢复为便利状态,便于上一层变换数字时调用
}
}
}
int main()
{
while(~scanf("%d%d",&n,&r))
{
memset(visit,false,sizeof(visit)); //初始化原始状态
DFS(n,1);
}
return 0;
}