读题!ヾ(*ΦωΦ)ツ
题目描述
排列与组合是常用的数学方法,其中组合就是从个元素中抽出个元素(不分顺序且),我们可以简单地将个元素理解为自然数从中任取r个数。
现要求你输出所有组合。
例如,所有组合为:
输入格式
一行两个自然数。
输出格式
所有的组合,每一个组合占一行且其中的元素按由小到大的顺序排列,每个元素占三个字符的位置,所有的组合也按字典顺序。
注意哦!输出时,每个数字需要3个场宽
输入输出样例
输入 #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选n,他这却是n选r,也好实现,多加一个变量就可以;上道题123、132、213、231、312、321是不同方法,此题却是一种方法,这就是我们最大的拦路虎。
别急,按照套路来,分析样例!!!
emm……看上去没啥规律,但我们找到了他们的共同点:后一个数总比前一个数大,前一个数不就是ans的第done项吗,比他大不就是加一吗?思路有了,开始码代码吧!
这是上一题的代码:
#include<bits/stdc++.h>//万能头文件
using namespace std;
int ans[25]={0},n;
int flag[25] = {1};
void rank(int done){//全排列
if(done==n){
for(int i = 0; i < n; i++){
cout << setw(5) << ans[i];
}
cout << endl;
return;
}
for(int i = 1; i <= n; i++){
if(flag[i] == 0){
flag[i] = 1;
ans[done]=i;
rank(done+1);
flag[i] = 0;
}
}
}
int main(int argc, char** argv) {
cin >> n;
rank(0);
return 0;
}
首先最上面的变量数组,去掉flag(后面的比前面的大当然不会重复咯),加上r:
int ans[100]={0},r,n;
接下来把终止条件改一下,改成r==done
,setw(5)
,代码:
if(r==done){
for(int i = 1; i <= r; i++){
cout << setw(3) << ans[i];
}
cout << endl;
return ;
}
最后,再把for循环i的值更改一下,if语句和flag赋值去掉。
for(int i = ans[done] + 1; i <= n; i++){
ans[done+1] = i;
rank(done+1);
}
函数搞定!
再把主函数改一下:
int main(int argc, char** argv) {
cin >> n >> r;
rank(0);
return 0;
}
完整代码
请勿抄袭!
#include<bits/stdc++.h>//万能头文件
#include <iostream>
#include <cstring>
#include <algorithm>
#include <math.h>
#include <cstdio>
using namespace std;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
int ans[100]={0},r,n;
void rank(int done){//全排列
if(r==done){
for(int i = 1; i <= r; i++){
cout << setw(3) << ans[i];
}
cout << endl;
return ;
}
for(int i = ans[done] + 1; i <= n; i++){
ans[done+1] = i;
rank(done+1);
}
}
int main(int argc, char** argv) {
cin >> n >> r;
rank(0);
return 0;
}
