菜鸡提升日记——递归枚举

枚举

题目来自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);
}

3.递归实现排列型枚举
在这里插入图片描述

#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.排列型枚举 可以往前遍历

猜你喜欢

转载自blog.csdn.net/aMonstere/article/details/108426970