组合数
时间限制:
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
分析:
假设有一个搜索函数dfs可以解决此问题
那么此问题可以分解为dfs(n,r),dfs(n-1,r),...dfs(r,r)
dfs(n,r)又可以分解为dfs(n-1,r-1),dfs(n-2,r-1),...dfs(r-1,r-1)
此函数一直往深处递归,直到两个参数n和r相等,或者r=1时返回上层。
每往深处递归一层,就能确定一位数,放到队列中。
当n和r相等时,直接能确定r个数,依次放到队列中,然后输出队列中存放的所有数字;
r=1时,也是输出,然后返回。
(我写的连自己也看不懂。。。直接看代码吧)
代码:
#include<cstdio> #include<deque> using namespace std; int vis[15]={0}; deque<int>p,q;/*由于队列的特殊性,输出的时候会清空所有数据,那么前几位数在以后的情况中不会输出。故使用2个队列,一个保存,一个输出。由于在返回以后要去掉刚刚输入到保存队列里的数据,用普通队列无法实现,故使用双端队列。*/ void dfs(int n,int r) { if(n==r) { for(int i=n;i>=1;i--) p.push_back(i); q=p; for(int i=n;i>1;i--)//留1个在返回后清除 p.pop_back(); while(!q.empty()) { printf("%d",q.front()); q.pop_front(); } printf("\n"); return; } p.push_back(n);//每层递归确定一位数 if(r==1) { q=p; while(!q.empty()) { printf("%d",q.front()); q.pop_front(); } printf("\n"); return; } for(int i=n-1;i>=r-1;i--) { dfs(i,r-1); p.pop_back(); } } int main() { int n,r; scanf("%d%d",&n,&r); for(int i=n;i>=r;i--) { dfs(i,r); p.pop_back(); } return 0; }