专题一——递归与递推

1. 92.递归实现指数型枚举

时间复杂度:O(n* 2 n 2^n 2n)

#include <bits/stdc++.h>

using namespace std;
const int N=16;
int n;
int st[N];
void dfs(int u)//u表示当前在做第几位
{
    if(u>n)
    {
        for(int i=1;i<=n;i++)
            if(st[i]==1) printf("%d ",i);
        puts("");
        return;
    }
    //枚举每一位的两种情况:1选 2不选
    st[u]=2;
    dfs(u+1);
    st[u]=0;

    st[u]=1;
    dfs(u+1);
    st[u]=0;
}
int main()
{
    cin>>n;
    dfs(1);
    return 0;
}

2.94. 递归实现排列型枚举

#include <bits/stdc++.h>

using namespace std;
const int N=10;
int state[N];//存放当前这一位的数
bool used[N];//记录哪个数用没用
int n;
void dfs(int u)
{
    if(u>n)
    {
        for(int i=1;i<=n;i++) printf("%d ",state[i]);
        puts("");
        return;
    }
    for(int i=1;i<=n;i++)
        if(!used[i])
    {
        state[u]=i;
        used[i]=true;
        dfs(u+1);
        state[u]=0;
        used[i]=false;
    }
}
int main()
{
    cin>>n;
    dfs(1);
    return 0;
}

3.93. 递归实现组合型枚举

方法一:模拟排列型枚举,多加一条判断语句【自己写的,贼慢】

#include <bits/stdc++.h>

using namespace std;
const int N=25;
int state[N];
bool used[N];
int n,m;
void dfs(int u)
{
    if(u>m)
    {
        for(int i=1; i<=m; i++) printf("%d ",state[i]);
        puts("");
        return;
    }
    for(int i=1; i<=n; i++)
    {
        if(!used[i])
        {
            state[u]=i;
            if(u>1&&state[u]<state[u-1]) continue;
            used[i]=true;
            dfs(u+1);
            state[u]=0;
            used[i]=false;

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

方法二:y总全新搜索方式

#include <bits/stdc++.h>
//与排列型的区别:不需要used数组,每次都比当前的数大的一位开始取
using namespace std;
const int N=30;
int n,m;
int way[N];
void dfs(int u,int start)//枚举第u位,从u位上的数字+1开始
{
    if(u+n-start<m) return;//剪枝:已经选好的数+可以选的数<应该选的数
    if(u==m+1)
    {
        for(int i=1;i<=m;i++) printf("%d ",way[i]);
        puts("");
        return;
    }
    for(int i=start;i<=n;i++)
    {
        way[u]=i;
        dfs(u+1,i+1);
        way[u]=0;
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    dfs(1,1);
    return 0;
}

4.1209. 带分数

dfs爆搜写法【by myself】

#include <bits/stdc++.h>

using namespace std;

int st[10];
bool used[10];
int m,res;
int strnu(int a[],int be,int en)
{
    int x=0;
    for(int i=be; i<=en; i++)
    {
        x=x*10+a[i];
    }
    return x;
}
void dfs(int u)//9个数全排列
{
    int n=9;
    if(u>n)//得到了全排列
    {   //循环时枚举要保证有3个数
        for(int i=1; i<n-1; i++)
        {
            for(int j=i+1; j<n; j++)
            {
                int a=strnu(st,1,i);
                int b=strnu(st,i+1,j);
                int c=strnu(st,j+1,n);
                if(a*c+b==c*m) res++;//除法的巧妙转化
            }
        }
        return;
    }
    for(int i=1; i<=n; i++)
    {
        if(!used[i])
        {
            st[u]=i;
            used[i]=true;
            dfs(u+1);
            st[u]=0;
            used[i]=false;
        }
    }
}
int main()
{
    scanf("%d",&m);
    dfs(1);
    printf("%d\n",res);
    return 0;
}

y总dfs嵌套写法

#include <bits/stdc++.h>

using namespace std;
const int N=10;
int n;
bool st[N],backup[N];
int ans;
bool check(int a,int c)
{
    long long b=n*(long long)c-a*c;
    if(!a||!b||!c) return false;
    memcpy(backup,st,sizeof st);
    while(b)//把b的每一位都抠出来
    {
        int x=b%10;
        b/=10;
        if(!x||backup[x]) return false;
        backup[x]=true;
    }
    for(int i=1;i<=9;i++)
        if(!backup[i]) return false;
    return true;
}
void dfs_c(int u,int a,int c)
{
    if(u>9) return;
    if(check(a,c)) ans++;
    for(int i=1;i<=9;i++)
        if(!st[i])
    {
        st[i]=true;
        dfs_c(u+1,a,c*10+i);
        st[i]=false;
    }
}
void dfs_a(int u,int a)
{
    if(a>=n) return;//直接没解
    if(a) dfs_c(u,a,0);
    for(int i=1;i<=9;i++)
        if(!st[i])
    {
        st[i]=true;
        dfs_a(u+1,a*10+i);
        st[i]=false;
    }
}
int main()
{
    cin>>n;
    dfs_a(0,0);
    cout<<ans<<endl;
    return 0;
}

5.717. 简单斐波那契

递推版本

#include <bits/stdc++.h>

using namespace std;
const int N=50;
int f[N];
int main()
{
    f[1]=0,f[2]=1;
    int n;
    cin>>n;
    for(int i=3;i<=n;i++) f[i]=f[i-1]+f[i-2];
    for(int i=1;i<=n;i++) printf("%d ",f[i]);
    return 0;
}

滚动数组版

#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

int main()
{
    int a = 0, b = 1;
    int n;
    cin >> n;

    for (int i = 0; i < n; i ++ )
    {
        cout << a << ' ';
        int c = a + b;
        a = b, b = c;
    }

    cout << endl;

    return 0;
}

6.95. 费解的开关【妙啊】

#include <bits/stdc++.h>

using namespace std;
const int N=6;
char g[N][N],backup[N][N];
int dx[5]={-1,0,1,0,0},dy[5]={0,1,0,-1,0};
void turn(int x,int y)//如何操作(x,y)格子及其四周使得01互换
{
    for(int i=0;i<5;i++)
    {
        int a=x+dx[i],b=y+dy[i];
        if(a<0||a>=5||b<0||b>=5) continue;
        g[a][b]^=1;
    }
}
int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        for(int i=0;i<5;i++) cin>>g[i];//先输入棋盘,字符串型
        int res=10;//记步数
        for(int op=0;op<32;op++)//枚举第一行灯的操作
        {
            memcpy(backup,g,sizeof g);
            int step=0;
            for(int i=0;i<5;i++)//看看第一行每一个格子是否需要操作
                if(op>>i&1)
                {
                    step++;
                    turn(0,i);
                }
            for(int i=0;i<4;i++)//下面的n-1行的操作都唯一确定了
                for(int j=0;j<5;j++)
                if(g[i][j]=='0')
            {
                step++;
                turn(i+1,j);
            }
            bool dark=false;//判断最后一行是否全部亮了
            for(int i=0;i<5;i++)
                if(g[4][i]=='0')
            {
                dark=true;
                break;
            }
            if(!dark) res=min(res,step);
            memcpy(g,backup,sizeof g);
        }
        if(res>6) res=-1;
        cout<<res<<endl;
    }
    return 0;
}

7.费解的开关升级版——116.飞行员兄弟

#include <bits/stdc++.h>

using namespace std;
typedef pair<int,int> PII;
const int N=5;
char g[N][N],backup[N][N];
int get(int x,int y)//二维数组到一维的映射
{
    return x*4+y;
}
void turn_one(int x,int y)
{
    if(g[x][y]=='+') g[x][y]='-';
    else g[x][y]='+';
}
void turn_all(int x,int y)
{
    for(int i=0;i<4;i++)
    {
        turn_one(x,i);
        turn_one(i,y);
    }
    turn_one(x,y);
}
int main()
{
    for(int i=0; i<4; i++)
        cin>>g[i];
    vector<PII> res;
    for(int op=0; op<1<<16; op++)
    {
        vector<PII> temp;
        memcpy(backup,g,sizeof g);
        for(int i=0; i<4; i++)
            for(int j=0; j<4; j++)
                if(op>>get(i,j)&1)
                {
                    temp.push_back({i,j});
                    turn_all(i,j);
                }
        bool has_closed=false;
        for(int i=0;i<4;i++)
            for(int j=0;j<4;j++)
            if(g[i][j]=='+')
            has_closed=true;
        if(has_closed==false)
        {
            if(res.empty()||res.size()>temp.size()) res=temp;
        }
        memcpy(g,backup,sizeof g);
    }
    cout<<res.size()<<endl;
    for(auto p: res)
        printf("%d %d\n",p.first+1,p.second+1);
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值