在中学中大家都学过排列组合问题,当时有一种方法叫枚举法,但费时费力。但计算机不这么认为,简单重复的事它最擅长,计算机是人类思维的延伸,现在让我们命令计算机去用排列组合枚举。
1.排列问题(输入n,输出1到n的全排列)
c++中有一个神奇的函数,能求数组的下一个字典序(next_permutation)和上一个字典序(prev_permutation)。
语法
next_permutation(首地址,尾地址+1)
代码如下
#include<bits/stdc++.h>
using namespace std;
int n;
int arr[100];
int main()
{
cin>>n;
for(int i=0;i<n;++i)
{
arr[i]=i+1;
}
do
{
for(int i=0;i<n;++i)
{
cout<<arr[i]<<" ";
}
cout<<endl;
}
while(next_permutation(arr,arr+n));
return 0;
}
下面是正经写的代码
先从1开始,创建一棵树,进行减枝操作,见下图(我真是灵魂画手希望能看懂
接下来就是2,3........n
这是一个问题套问题,大问题里有小问题的问题,且大问题和小问题的解决方式一样,可以考虑递归。
#include<bits/stdc++.h>
using namespace std;
int n;
int arr[10];//存放数据
bool brr[10]={0};//用于判断数字有没有用过
void pai(int k)//k为递归次数
{
if(k==n)//第n次递归已选出所有数字
{
for(int j=1;j<=n;++j)
{
cout<<setw(5)<<arr[j];//输出
}
cout<<endl;
}
for(int i=1;i<=n;++i)
{
if(brr[i]==0)//判断是否被用过
{
brr[i]=1;//标记
arr[k+1]=i;//对数组赋值
pai(k+1);//开始递归
brr[i]=0;//回溯时记得清理brr数组,很重要。
}
}
}
int main() {
cin>>n;
pai(0);//函数调用,从0开始,正好次递归
return 0;
}
2.组合问题(从1到n中选出k个数,输出所有情况)
排列数有了,组合数怎么能没有呢。
在输出时我们可以采用降序输出来避免重复输出,也就是后一个数总比钱一个数大。这也是一个问题套问题,大问题里有小问题的问题,且大问题和小问题的解决方式一样,可以考虑递归。
当输入6 3时输出顺序为123 124 125 134 135 145 234 235....按照规律搜索和回溯
code如下
#include<bits/stdc++.h>
using namespace std;
int n,k;
int arr[30];
void dfs(int m,int s)//这里的s保证arr中的数降序排列
{
if(m==k)//第k个数已选完
{
for(int i=0;i<k;++i)
{cout<<setw(3)<<arr[i];//输出
}
cout<<endl;
return;//如输入了6 3输出了123后会返回变为124后面是125再是134,依次类推
}
for(int i=s;i<n;++i)
{
arr[m]=i+1;///数组赋值
dfs(m+1,i+1);//开始递归
}
}
int main()
{
cin>>n>>k;
dfs(0,0);//开始调用
return 0;
}
收工
希望大家都能学会(~--v--)~