递归与递推

本文介绍了如何使用递归解决不同类型的枚举问题,包括通过递归实现斐波那契数列,使用递归和二进制右移法进行指数型枚举,以及递归和函数法处理排列和组合问题。同时,文章还探讨了剪枝技术在组合型枚举中的应用,确保选择方案的升序性。
摘要由CSDN通过智能技术生成

递归

所有递归都可以画递归搜索树来理解

例如斐波那契数列:

实现指数型枚举

例:从 1∼n 这 n 个整数中随机选取任意多个,输出所有可能的选择方案。

递归法:
#include<iostream>
#include<cstdio>

using namespace std;

const int N=18;
int st[N],n; //1选 0不选

void dfs(int u)
{
    if(u==n)
    {
        for(int i=0;i<n;i++)
            if(st[i]==1) printf("%d ",i+1);
        puts("");
        return ;
    }
    
    st[u]=0;
    dfs(u+1);
    st[u]=1;
    dfs(u+1);
}

int main()
{
    cin>>n;
    
    dfs(0);
    
    return 0;
}
二进制右移法:
#include<iostream>

using namespace std;

int main()
{
    int n;
    scanf("%d",&n);
    int v=1;
    for(int i=0;i<n;i++) v*=2;
	for(int op=0;op<v;op++)
	{
	    for(int i=0;i<n;i++)
	    {
	        if(op>>i&1) printf("%d ",i+1); 
	    }
	    puts("");
	}
	
	return 0;
}

实现排列型枚举

例:把 1∼n 这 n 个整数排成一行后随机打乱顺序,输出所有可能的次序

递归法:
#include<iostream>
#include<cstdio>

using namespace std;

const int N=11;
int way[N],st[N],n; //st 0可用 1不可用

void dfs(int u)
{
    if(u==n)
    {
        for(int i=0;i<n;i++)
            printf("%d ",way[i]);
        puts("");
        return;
    }
    
    for(int i=1;i<=n;i++)
    {
        if(st[i]==0)
        {
            way[u]=i;
            st[i]=1;
            dfs(u+1);
            st[i]=0;
        }
    }
}

int main()
{
    cin>>n;
    
    dfs(0);
    
    return 0;
}
函数法:

函数头文件<algorithm>

bool next_permutation(iterator start,iterator end)

next_permutation函数求当前排列的下一个排列,这里指按照字典序排列,不存在下一个排列时返回false

prev_permutation相反,求的是当前排列的上一个排列

#include<iostream>
#include<cstdio>
#include<algorithm>

using namespace std;

const int N=11;
int a[N];

int main()
{
    int n;
    cin>>n;
    
    for(int i=0;i<n;i++) a[i]=i+1;
    
    do
    {
        for(int i=0;i<n;i++) printf("%d ",a[i]);
        puts("");
    }while(next_permutation(a,a+n));
    
    return 0;
}

实现组合型枚举

例:从 1∼n 这 n 个整数中随机选出 m 个,输出所有可能的选择方案,保证方案为升序

剪枝法:
#include<iostream>
#include<cstdio>

using namespace std;

const int N=30;
int way[N],st[N],n,m;

void dfs(int u)
{
    if(u==m)
    {
        for(int i=0;i<m;i++) printf("%d ",way[i]);
        puts("");
        return;
    }
    
    for(int i=1;i<=n;i++)
    {
   	 if(n-i<m-u-1) return; //剪枝:剩下的n-i个数不足够填
        if(st[i]==0&&(i>way[u-1]||u==0)) //剪枝:不满足升序
        {
            way[u]=i;
            st[i]=1;
            dfs(u+1);
            st[i]=0;
        }
    }
}

int main()
{
    cin>>n>>m;
    
    dfs(0);
    
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值