第一章:递推与递归 【完结】

本文通过递归实现指数型枚举、排列型枚举和组合型枚举,以及解决斐波那契数列、开关问题、翻硬币和带分数等经典问题,深入理解递归和枚举在算法中的应用。代码详实,适合初学者巩固递归思想和实战训练。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目前,这一章都已经熟练掌握了。

在用递归的时候可以先画一个递归树来分析。

92. 递归实现指数型枚举 【板子题】

在这里插入图片描述
题目详解

#include<bits/stdc++.h>
using namespace std;
int a[30],vis[30],n;
void dfs(int index)
{
    if(index==n)
    {
        for(int i=0;i<n;i++) if(vis[i]==1) cout<<i+1<<" ";
        cout<<endl;
        return;
    }
    vis[index]=1;//选
    dfs(index+1);
    
    vis[index]=0;//不选
    dfs(index+1);
}
int main(void)
{
    cin>>n;
    dfs(0);
    return 0;
}

注意: 递归一定要恢复现场。

94. 递归实现排列型枚举 【板子题】

在这里插入图片描述
题目详解

#include<cstdio>
#include<iostream>
int state[10];//0代表还没有选数,1~n代表放了哪个数 
bool m[10];//true表示用过,false表示没有用过 
int n;
void dfs(int u)//第几个位置 
{
	if(u==n)
	{
		for(int i=0;i<n;i++)
		{
			printf("%d ",state[i]);
		}
		printf("\n");
		return;
	}
	for(int i=1;i<=n;i++)//枚举所有的数,看哪个可以选 
	{
		if(!m[i])//该数没有被选 
		{
			m[i]=true;//状态表示选了 
			state[u]=i;//选这该数 
			dfs(u+1);//开始选下一个位置 
			
			m[i]=false;//恢复现场 
			state[u]=0;//恢复现场 
		}
	}
}
int main(void)
{
	scanf("%d",&n);
	dfs(0);
	return 0;
} 

可以用现有的函数实现全排列

#include<cstdio>
#include<algorithm>
using namespace std;
int a[10]={1,2,3,4,5,6,7,8,9};
int main(void)
{
    int n;
    scanf("%d",&n);
    do
    {
        for(int i=0;i<n;i++)
        {
            printf("%d ",a[i]);
        }
        printf("\n");
    }while(next_permutation(a,a+n));
    return 0;
}

93. 递归实现组合型枚举【板子题】

在这里插入图片描述
题目详解
代码如下:

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
int m,n;
int ways[30];
void dfs(int u,int start)//u 代表当前是第几位  start表示选的数从哪里开始遍历 
{
	if(u==m+1)//选够了 
	{
		for(int i=1;i<=m;i++)
		{
			printf("%d ",ways[i]);
		}
		puts("");//回车,这是一种比printf() 简单的写法
		return; 
	}
	for(int i=start;i<=n;i++)//枚举元素 
	{
		ways[u]=i;
		dfs(u+1,i+1);
		
		ways[u]=0;//恢复现场 
	}
}
int main(void)
{
	cin>>n>>m;
	dfs(1,1);
	return 0;
}
#include<bits/stdc++.h>
using namespace std;
int a[30],vis[30],n,m;
void dfs(int index,int start)
{
    if(index==m)
    {
        for(int i=0;i<m;i++) cout<<a[i]<<" ";
        cout<<endl;
        return;
    }
    for(int i=start;i<=n;i++)
    {
        if(!vis[i])
        {
            a[index]=i;
            vis[i]=1;
            dfs(index+1,i);
            vis[i]=0;
        }
    }
}
int main(void)
{
    cin>>n>>m;
    dfs(0,1);
    return 0;
}

717. 简单斐波那契 【简单 / 递推】

在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
const int N=1010;
typedef long long int LL;
LL a[N],n;
int main(void)
{
    cin>>n;
    a[1]=0,a[2]=1;
    for(int i=3;i<=n;i++) a[i]=a[i-1]+a[i-2];
    for(int i=1;i<=n;i++) cout<<a[i]<<" ";
    return 0;
}

95. 费解的开关 【二进制枚举 / 递推】

在这里插入图片描述
题目详解

#include<bits/stdc++.h>
using namespace std;
int a[30][30],b[30][30],n;
int dx[5]={0,-1,0,1,0};
int dy[5]={0,0,1,0,-1};
void turn(int x,int y)
{
    for(int i=0;i<5;i++)
    {
        int tempx=x+dx[i];
        int tempy=y+dy[i];
        if(tempx>=0&&tempx<5&&tempy>=0&&tempy<5) b[tempx][tempy]^=1;
    }
}
int dfs()
{
    int ans=10;
    for(int k=0;k<32;k++)
    {
        int cnt=0;
        memcpy(b,a,sizeof b);
        for(int i=0;i<5;i++) if(k>>i&1) turn(0,i),cnt++;
        
        for(int i=1;i<5;i++)
            for(int j=0;j<5;j++) if(!b[i-1][j]) turn(i,j),cnt++;
        bool flag=true;
        for(int i=0;i<5;i++) if(!b[4][i]) flag=false; //判断最后一排是不是都是亮的 
        if(flag) ans=min(ans,cnt);
    }
    if(ans>6) return -1;
    else return ans;
}
int main(void)
{
    cin>>n;
    while(n--)
    {
        string s[10];
        for(int i=0;i<5;i++) cin>>s[i];
        for(int i=0;i<5;i++)
            for(int j=0;j<5;j++)
                a[i][j]=s[i][j]-'0';
        cout<<dfs()<<endl;
    }
    return 0;
}

1208. 翻硬币 【递推】

在这里插入图片描述
题目详解

#include<bits/stdc++.h>
using namespace std;
string a,b;
int main(void)
{
    cin>>a>>b;
    int ans=0;
    for(int i=1;i<b.size();i++)
    {
       if(b[i-1]!=a[i-1])
        {
           b[i-1]=a[i-1];
           if(b[i]=='*') b[i]='o';
           else b[i]='*';
           ans++;
        }
    }
    cout<<ans;
    return 0;
}

116. 飞行员兄弟 【二进制枚举 】

在这里插入图片描述
题目详解

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
int a[10][10],b[10][10];
void turn(int x,int y)
{
    for(int i=0;i<4;i++) b[x][i]^=1,b[i][y]^=1;
    b[x][y]^=1;//按了两次得再按一次
}
int main(void)
{
    string s[10];
    for(int i=0;i<4;i++) cin>>s[i];
    for(int i=0;i<4;i++)
        for(int j=0;j<4;j++)
            if(s[i][j]=='+') a[i][j]=0;
            else a[i][j]=1;
     
    vector<PII> ans;
    
    for(int i=0;i<(1<<16);i++)
    {
        vector<PII>temp;
        memcpy(b,a,sizeof a);
        for(int j=0;j<16;j++)
        {
            if( (i>>j) & 1 )
            {
                turn(j/4,j%4);
                temp.push_back({j/4,j%4});
            }
        }
        bool flag=true;
        for(int j=0;j<4;j++)
            for(int k=0;k<4;k++)
                if(!b[j][k]) flag=false;
        
        if(flag && ( ans.size()>temp.size() || ans.empty() ) ) ans=temp;
    }
    cout<<ans.size()<<endl;
    for(auto op: ans) cout<<op.first+1<<" "<<op.second+1<<endl;
    return 0;
}

1209. 带分数 【枚举】

在这里插入图片描述
详细解析

#include<bits/stdc++.h>
using namespace std;
int a[10],ans;
int get(int l,int r)
{
    int sum=0;
    for(int i=l;i<=r;i++) sum=sum*10+a[i];
    return sum;
}
int main(void)
{
    int n; cin>>n;
    for(int i=1;i<=9;i++) a[i]=i;
    do
    {
        for(int i=1;i<=7;i++)
        {
            for(int j=i+1;j<=8;j++)
            {
                int a=get(1,i);
                if(a>n) continue;
                int b=get(i+1,j);
                int c=get(j+1,9);
                if(b%c==0&&a+b/c==n) ans++;
            }
        }
    }while(next_permutation(a+1,a+10));
    cout<<ans;
    return 0;
}

acwing会TLE 其它oj可以过

#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
int n;
string s="123456789";
int main(void)
{
	cin>>n;
	int cnt=0;
	do
	{
		for(int i=1;i<=7;i++)
		{
			int a=stoi(s.substr(0,i));
			if(a>n) continue;
			for(int j=1;j<=8-i;j++)
			{
				int b=stoi(s.substr(i,j));
				int c=stoi(s.substr(i+j));
				if(b%c!=0) continue;
				else
				{
					if(a+b/c==n)  cnt++;
				}
			}
		}
	}while(next_permutation(s.begin(),s.end()));
	printf("%d\n",cnt);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值