蓝桥杯必考算法递归以及相关题目

📟作者主页:慢热的陕西人

🌴专栏链接:力扣刷题日记

📣欢迎各位大佬👍点赞🔥关注🚓收藏,🍉留言

1.复杂度

image-20240219224124836

2.递归

2.1递归实现指数型枚举

image-20240219230437880

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

using namespace std;

#define N 16

int st[N];

int n;

void dfs(int u) //0表示空,1表示不选,2表示选
{
    if(u > n)
    {
        for(int i = 1; i <= n; ++i)
        if(st[i] == 2)
        printf("%d ", i);
        
        printf("\n");
        
        return;
    }
    
    st[u] = 1; //表示我们不选第u个数字
    dfs(u + 1);
    
    st[u] = 0; //恢复数组
    
    st[u] = 2; //表示我们选第u个数字
    dfs(u + 1);
    
    st[u] = 0; // 最后恢复数组
}

int main()
{
    cin >> n;
    
    dfs(1); //表示遍历到第0位
    
    
    return 0;
}

2.2递归实现排列型枚举

image-20240219235916994

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

using namespace std;

#define N 10

int state[N]; //0表示未用,1表示使用

int ways[N]; //存储我们的答案

int n;

void dfs(int u)
{
    if(u > n) //边界
    {
        for(int i = 1; i <= n; ++i)
        printf("%d ", ways[i]);
        
        printf("\n");
        
        return;
    }
    
    for(int i = 1; i <= n; ++i)
    {
        if(state[i] == 0)
        {
            state[i] = 1; //表示占用了u
            ways[u] = i; //将u加入到答案
            
            dfs(u + 1);  //遍历下一个位置
            
            ways[u] = 0;
            
            state[i] = 0; //恢复现场
        }
        
        
    }
}

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

2.3递归实现组合型枚举

两种方法解决:

  • 将例一不符合长度的答案去掉即可
  • 只需要满足答案的前一个数字比后一个数字大即可
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>

using namespace std;

#define M 25


int ways[M]; //存储我们的答案

int n,m;

void dfs(int u, int st)
{
    if(n + u - st < m)  return; //剪枝,选上后面的所有的数都不够答案的数量
    
    if(u == m + 1)
    {
        for(int i = 1; i <= m; ++i)
        printf("%d ", ways[i]);
        
        printf("\n");
        
        return;
    }
    
    for(int i = st; i <= n; ++i)
    {
        ways[u] = i;
        dfs(u + 1, i + 1); //从大于当前插入的数字开始遍历
        ways[u] = 0;
    }
}

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

2.4带分数

链接:[P1426 - 蓝桥杯]带分数 - New Online Judge (ecustacm.cn)

[P8599 蓝桥杯 2013 省 B] 带分数 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

思路: 设 n = a + b / c,化简为 n * c = a * c + b;

那么我们先寻找a, 在a的基础上寻找c, 在a,c已知的情况下,去计算b。

细节注意要b的类型longlong,不然只能过部分。

因为算法需要去枚举答案,所以选用了递归的思路。

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

using namespace std;

#define N 10

bool st[N], buckup[N];

int ans;

int n;

bool check(int a, int c)
{
 long long b = (long long)c * n - c * a;  //注意数据的大小,部分ac!!!!

 if(!a || !b || !c) return false; //优化存在零的话直接返回错误

 memcpy(buckup, st, sizeof st);

 while(b)
 {
     int x = b % 10; //取个位
     b /= 10; //去掉个位
     if(!x || buckup[x]) return false; //存在0,或者对应的数字已经被占用则不是答案
     buckup[x] = true;
 }

 for(int i = 1; i <= 9; ++i)
     if(!buckup[i]) return false;
 return true;
}


void dfs_c(int u, int a, int c)
{
 if(u == n) return; //当位数达到9位的时候,代表无解

 if(check(a, c)) ans++; //检查当前a,c的值,存在一个b成立,则使得答案++

 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); //计算当前a下,c的值,c的值从零开始

 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); //表示从第零开始,a = 0;

 cout << ans << endl;

 return 0;
}

2.5费解的开关:

95. 费解的开关

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

using namespace std;

int dx[6] = { -1, 0, 1, 0, 0 }, dy[6] = { 0, 1, 0, -1, 0 };
char g[6][6], bk[6][6];

void turn(int x, int y)
{
    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 n;
    cin >> n;
    while (n--)
    {
        int res = 10; //设置一个较大的值

        for (int i = 0; i < 5; ++i) cin >> g[i];

        for (int op = 0; op < 32; ++op) //第一行的32种可能
        {
            memcpy(bk, g, sizeof(g));
            int step = 0; //设置当前的步数为0
            //1.先按第一行
            for (int i = 0; i < 5; ++i)
                if (op >> i & 1)
                {
                    step++;
                    turn(0, i); //反转[1,i + 1];
                }


            //2.接下来处理剩下的234行
            for (int i = 0; i < 4; ++i)
                for (int j = 0; j < 5; ++j)
                {
                    if (g[i][j] == '0')
                    {
                        step++;
                        turn(i + 1, j);
                    }
                }

            //3.检查第五行是否全亮
            bool black = false;
            for (int j = 0; j < 5; ++j)
            {
                if (g[4][j] == '0')
                {
                    black = true;
                    break;
                }
            }

            
            if (!black) res = min(res, step);
            memcpy(g, bk, sizeof(g));
        }

        if (res > 6) res = -1;
        cout << res << endl;
        
    }
    return 0;
}

2.6翻硬币

题目链接:[P1428 - 蓝桥杯]翻硬币 - New Online Judge (ecustacm.cn)

思路:

将两个符号之间看作一个开关,那么两个符号改变,就相当于中间的按钮被按下。

那么左边的符号需要被改变,那么一定是中间的按钮需要被按下,并且一个按钮如果被按了两次,相当于没有被按下

image-20240225230236559

#include<iostream>
#include<cstring>
   
using namespace std;
   
const int N = 110;
   
char start[N], dest[N];
   
void turn(int i)
{
    if(start[i] == 'o') start[i] = '*';
    else start[i] = 'o'
}
   
int main()
{
    cin >> start >> dest;
       
    int n = strlen(start);
       
    int res = 0;
       
    for(int i = 0; i < n - 1; ++i)
    {
        if(start[i] != dest[i])
        {
            turn(i), turn(i + 1);
            res++;
        }
    }
       
    cout << res;
    return 0;
}

2.7飞行员兄弟

题目链接:116. 飞行员兄弟 - AcWing题库

思路:数据量小,所以枚举所有的结果,然后找出步数最少的那个。

image-20240225232025783

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

#define x first
#define y second

using namespace std;

typedef pair<int,int> PII;

const int N = 5;

char g[N][N], bku[N][N];

int get(int x, int y) //通过坐标获取对应的序号
{
    return 4 * x + 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; //存储答案的数组,每个元素都是一个pair
    
    for(int op = 0; op < 1 << 16; op++) //遍历2的16次方种可能
    {
        vector<PII> temp;
        memcpy(bku, 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, bku, sizeof g);
    }
    
    cout << res.size() << endl;
    
    for(auto op : res) cout << op.x + 1 << ' ' << op.y + 1 << endl;
    
    return 0;
}
  • 28
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 11
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小米睡不醒.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值