AcWing 93. 递归实现组合型枚举 递归模板

AcWing 93. 递归实现组合型枚举

从 1~n 这 n 个整数中随机选出 m 个,输出所有可能的选择方案。

输入格式
两个整数 n,m ,在同一行用空格隔开。

输出格式
按照从小到大的顺序输出所有方案,每行1个。

首先,同一行内的数升序排列,相邻两个数用一个空格隔开。

其次,对于两个不同的行,对应下标的数一一比较,字典序较小的排在前面(例如1 3 5 7排在1 3 6 8前面)。

数据范围
n>0 ,
0≤m≤n ,
n+(n−m)≤25
输入样例:

5 3

输出样例:

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 

思考题:如果要求使用非递归方法,该怎么做呢?

这道题对我们来说应不是很难,但是我第一次开始的时候用的是状态压缩试了一下。

#include

using namespace std;

int main(void)
{
     
    int n,m;
    cin>>n>>m;
    for(int i=0;i<1<<n;i++)
    {
     
        int cnt=0;
        for(int j=0;j<n;j++)
        {
     
            if(i>>j&1)
            cnt++;
        }
        if(cnt==m)
        {
     
            for(int j=0;j<n;j++)
            {
     
                if(i>>j&1)
                printf("%d ",j+1);
            }
            puts("");
        }
    }
}

这个方法是可以枚举出所有的组合,但是。
AcWing 93. 递归实现组合型枚举 递归模板_第1张图片
仔细观察的话就发现,其实顺序不是很对。
我就用递归试了一下,写了这个代码

#include

using namespace std;

int main(void)
{
     
    int n,m;
    cin>>n>>m;
    for(int i=0;i<1<<n;i++)
    {
     
        int cnt=0;
        for(int j=0;j<n;j++)
        {
     
            if(i>>j&1);
            else
            cnt++;
        }
        if(cnt==m)
        {
     
            for(int j=n-1;j>=0;j--)
            {
     
                if(i>>j&1);
                else
                printf("%d ",n-j);
            }
            puts("");
        }
    }
}

其实这是AC了,但是我觉得时间复杂度很高,而且还有很多判断过程应该不是最优解。
在这里插入图片描述

然后我就试试不用递归,稍微改了一下代码。

#include

using namespace std;

const int N=30;

int arr[N];
int n,m;
bool st[N];

void dfs(int x)
{
     
    if(x==m+1)
    {
     
        for(int i=1;i<=m;i++)
        printf("%d ",arr[i]);
        puts("");
        return;
    }
    for(int i=1;i<=n;i++)
    {
     
        if(!st[i]&&i>arr[x-1])
        {
     
            arr[x]=i;st[i]=true;
            dfs(x+1);
            st[i]=false;
        }
    }
}

int main(void)
{
     
    cin>>n>>m;
    dfs(1);
    return 0;
}

这个也是AC的,这个表现还是不错的,没有调用函数。
在这里插入图片描述
我觉得这些都不是最好的,看了y总的视频之后,我觉得我的代码太垃圾了。
学完后的代码

#include

using namespace std;

const int N=30;

int arr[N];
int n,m;

void dfs(int x,int st)
{
     
    if(x+n-st<m) return;
    if(x==m+1)
    {
     
        for(int i=1;i<=m;i++)
        printf("%d ",arr[i]);
        puts("");
        return;
    }
    for(int i=st;i<=n;i++)
    {
     
        arr[x]=i;
        dfs(x+1,i+1);//每次枚举完,从i+1点开始。
        arr[x]=0;
    }
    return;
}

int main(void)
{
     
    cin>>n>>m;
    dfs(1,1);
    return 0;
}

在这里插入图片描述
这个运行时间确实真的太理想了。

你可能感兴趣的