枚举
题目来自acwing
1.递归实现指数型枚举
1.保证答案中升序,需要保证备选数组中数字为升序,题目为自然数1-n不用考虑排序,但是需要一个start来确定每次放入答案数组中的数字从多少开始。
2.输出每一种方案,需要设立0-n个边界值(n为空集)
#include<bits/stdc++.h>
using namespace std;
int ans[20];
int n;
void dfs(int pos,int start,int cur)//start 确保升序,
{
if(pos==cur)
{
for(int i=0; i<cur; i++)
{
i==0||printf(" ");
printf("%d",ans[i]);
}
printf("\n");
}
for(int i=start; i<=n; i++) //从1开始进行枚举
{
ans[pos]=i;
dfs(pos+1, i+1, cur);
}
}
int main()
{
cin>>n;
for(int i=0; i<=n; i++) //每个方案中数字的数量
dfs(0,1,i);
}
变体:
加入数组
1.备选数组排序;
2.答案中避免降序,用start限制每一次循环的开始
3.边界从0到n依次代表从空集,到全集
4.避免相同数字进入答案,重复的数字,要么是第一次要选的,要么是与前一数字不重复的,重复的数字会在arry[i]!=arry[i-1]处被筛出
#include<bits/stdc++.h>
using namespace std;
int ans[20];
int arry[20];
int n;
void dfs(int pos,int start,int cur)//start 确保升序,
{
if(pos==cur)
{
for(int i=0; i<cur; i++)
{
i==0||printf(" ");
printf("%d",ans[i]);
}
printf("\n");
}
for(int i=start; i<n; i++) //从1开始进行枚举
{
if(i==start||arry[i]>arry[i-1])
{
ans[pos]=arry[i];
dfs(pos+1, i+1, cur);
}
}
}
int main()
{
cin>>n;
for(int i=0; i<n; i++)
cin>>arry[i];
sort(arry,arry+n);
for(int i=0; i<=n; i++) //每个方案中数字的数量
dfs(0,0,i);
}
2.递归实现组合型枚举
1.相邻升序,start来限制下一个出现的数字
#include<bits/stdc++.h>
using namespace std;
int ans[30];
int m,n;
void dfs(int pos,int start)
{
if(pos==m)
{
for(int i=0; i<pos; i++)
{
i==0||printf(" ");
printf("%d",ans[i]);
}
printf("\n");
}
else
{
for(int i=start; i<=n; i++)
{
ans[pos]=i;
dfs(pos+1,i+1);
}
}
}
int main()
{
cin>>n>>m;
dfs(0,1);
}
#include<bits/stdc++.h>
using namespace std;
int ans[30];
int arry[30];
int n,m;
void dfs(int pos,int start)
{
if(pos==m)
{
for(int i=0;i<m;i++)
{
i==0||printf(" ");
printf("%d",ans[i]);
}printf("\n");
}
else
{
for(int i=start;i<n;i++)
{
if(i==start||arry[i]!=arry[i-1])
{
ans[pos]=arry[i];
dfs(pos+1,i+1);
}
}
}
}
int main()
{
cin>>n>>m;
for(int i=0;i<n;i++)
{
cin>>arry[i];
}
sort(arry,arry+n);
dfs(0,0);
}
#include<bits/stdc++.h>
using namespace std;
int ans[10];
int vis[10];
int n;
void dfs(int pos)
{
if(pos==n)
{
for(int i=0;i<n;i++)
{
i==0||printf(" ");
printf("%d",ans[i]);
}printf("\n");
}
else
{
for(int i=1;i<=n;i++)
{
if(!vis[i])
{
vis[i]=1;
ans[pos]=i;
dfs(pos+1);
vis[i]=0;
}
}
}
}
int main()
{
cin>>n;
dfs(0);
}
1.每一组数据,为任意排序,而非顺序,采用cnt数组计数
2.采用i==0||arry[i]!=arry[i-1]去重
#include<bits/stdc++.h>
using namespace std;
int ans[10];
int arry[10];
int cnt[10];
int n;
void dfs(int pos)
{
if(pos==n)
{
for(int i=0;i<n;i++)
{
i==0||printf(" ");
printf("%d",ans[i]);
}printf("\n");
}
else
{
for(int i=0;i<n;i++)
{
if(cnt[arry[i]]&&(i==0||arry[i]!=arry[i-1]))
{
cnt[arry[i]]--;
ans[pos]=arry[i];
dfs(pos+1);
cnt[arry[i]]++;
}
}
}
}
int main()
{
cin>>n;
for(int i=0;i<n;i++)
{
cin>>arry[i];
cnt[arry[i]]++;
}
sort(arry,arry+n);
dfs(0);
}
Summary
对于枚举
1.需要升序,采用start
2.若引用数组,需要去重 加 i==(初始)||arry[i]!=arry[i-1];
3.每一方案,主函数加for循环,从0-n依次为答案边界
4.无序排列需要引用计数数组(数组中有重复情况)/访问数组(数组中数字单一)
5.指数型枚举 边界不固定
6.组合型枚举 边界固定
7.排列型枚举 可以往前遍历