排列和组合枚举都是暴力基础啦,虽然很简单但是总结一下比较好
组合
先从简单的说起吧,比如说从n个数里选k个
先放代码:
void combination(int cur,int cnt)//cur为当前数,cnt为已选择数的个数
{
if(cnt==k) return ;
for(int i=cur;i<=n;i++)
{
dfs(i+1,cnt+1);
}
}
conbination(1,0);
(这里的n, k, cur, cnt均指序号)
这种思路并不难理解,要保证每一位数前面都没有出现,可以直接从小到大,每一位都枚举上一位后面的数,通过递归就能把所有的组合都枚举出来啦。
排列
最准确的排列算法是通过一步步进化来的
Again,比方说从n个数里选出k个进行排列
最傻白甜的一个写法:
bool check(int i,int n)
{
for(int j=1;j<n;j++)
{
if(a[j]==i) return false;
}
return true;
}
void permutation(int cnt)
{
if(cnt==k+1) return ;
for(int i=1;i<=n;i++)
{
if(check(i,cnt))
{
a[cnt]=i;
permutation(cnt+1);
}
}
}
permutation(1);
通过前面的数字检查有没有重复,来实现每一次枚举不同的数。
然而这种写法是建立在原数组中本身没有重复数字的先决条件下的,但如果有重复的数字就gg了。
比如{1,2,3,4}可以但{1,1,3,4}不行
所以我们会想到开一个计数器Ci,记录每个数字一共出现了几次。
然后这样:
bool check(int i,int n,int c1)
{
int c2;
for(int j=1;j<n;j++)
{
if(a[j]==i) c2++;
}
if(c1>c2) return true;
if(c1<=c2) return false;
}
void permutation(int cnt)
{
if(cnt==k+1) return ;
for(int i=1;i<=n;i++)
{
if(check(i,cnt,c[i]))
{
a[cnt]=i;
permutation(cnt+1);
}
}
}
挺麻烦的,但是能做对但是,如果去考试的话,C++里其实有库可以直接用...
一个叫next_permutation的神奇函数
这时我们假设将要排列枚举的数组为P
#include<iostream>
#include<algorithm>//算法头文件
using namespace std;
int main()
{
/*输入就不写了*/
sort(p+1,p+n+1); //需要从小到大排列时要先排序
do{
//对当前排列的顺序操作
} while(next_permutation(p+1,p+n+1));
return 0;
}
(还有这种操作???.jpg)