ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

蓝桥杯 第一讲 递归与递推

2022-01-07 19:04:45  阅读:119  来源: 互联网

标签:递归 int backup dfs st 蓝桥 ++ include 递推


92. 递归实现指数型枚举

image

dfs递归做法

#include<iostream>
using namespace std;
const int N = 20;

int n;
bool st[N]; //1~N每个数的状态数组:0表示未选择,1表示已选择
void dfs(int u)
{
    if(u >= n) //递归出口:深搜到第n+1位,打印该方案
    {
        for(int i=0;i < n;i++)
        {
            if(st[i])//选择该数就打印
            {
                cout<<i+1<<" ";
            }
        }
        puts("");
        return;
    }
    
    st[u] = true; //第一个分支:选择该数
    dfs(u+1);
    st[u] = false; //dfs必须恢复状态
    dfs(u+1);//第二个分支:不选该数
}
int main()
{
    cin>>n;
    dfs(0);
    return 0;
}

二进制数位循环枚举做法

#include<iostream>
using namespace std;
const int N = 20;

int n;
int a[N] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20};
int main()
{
    cin>>n;
    for(int i=0;i < 1<<n;i++)
    {
        int t = i;
        for(int j=0;j<n;j++)
        {
            if(t%2 == 1) cout<<a[j]<<" ";
            t = t>>1;
        }
        puts("");
    }
    return 0;
}

94. 递归实现排列型枚举

image
O(n!*n)

#include<iostream>

using namespace std;
const int N = 10;

bool st[N];//1~N中每个数是否被使用
int n;
int a[N];//方案
void dfs(int u)//枚举到第几位
{
    if(u >= n) //已经枚举完最后一位
    {
        for(int i=0;i<n;i++)
        {
            cout<<a[i]<<" ";//输出方案
        }
        puts("");
        return;
    }
    for(int i=1;i<=n;i++) //从小到大枚举每个数
    {
        if(!st[i]) //没有被用过
        {
            st[i] = true; //标记使用
            a[u] = i;//记录到方案中
            dfs(u+1);//搜索下一位

            st[i] = false; //下一层搜索回来,恢复状态
        }
    }
}
int main()
{
    cin>>n;
    dfs(0);
    return 0;
}

93. 递归实现组合型枚举

y总写法

#include<iostream>

using namespace std;

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

void dfs(int u,int st) //u是第几位,st是从哪个数开始枚举
{
    if(n - st < m - u) return;//剪枝:当前剩余待选的数的个数小于空位数
    if(u == m + 1)
    {
        for(int i=1;i<=m;i++)
        {
            cout<<way[i]<<" ";
        }
        puts("");
    } 
    
    way[u] = st;
    dfs(u+1,st+1);
    dfs(u+1,st)
}
int main()
{
    cin>>n>>m;
    dfs(1,1);
}

我的写法

#include<iostream>

using namespace std;

const int N = 25;
int n,m;
bool st[N];
void dfs(int x,int t) //x表示选择的数,t表示已选择的数的个数
{
   if(t >= m) //选够了,就输出方案
   {
       for(int i=1;i<=n;i++)
       {
            if(st[i]) cout<<i<<" ";  
       }
       puts("");
       return;
   }
   if(x > n) return;//选择的数不大于n
   st[x] = true;//选择x
   dfs(x+1,t+1);//保证每次新加的数大于前一个数,升序
   st[x] = false;//不选择x
   dfs(x+1,t);
}
int main()
{
    cin>>n>>m;
    dfs(1,0);
    return 0;
}

1209. 带分数

image

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 20;

bool st[N];
bool backup[N];
int n,ans;

bool check(int a,int c)
{
    int b = n*c - a*c;//根据题意求出b的大小
    if(a==0 || b==0 || c == 0) return false;//a,b,c不允许任何一个为0
    memcpy(backup,st,sizeof st);//check函数需要单独的判重数组
    while(b)//枚举b的每一位
    {
        int a = b % 10;
        b /= 10;
        if(a == 0 || backup[a] == true) return false;//若为0或者已经使用过的数,则失败
        backup[a] = 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 >= 10) return;//1~9所有数字用完了
    if(check(a,c)) ans++;//检查当前a和c是否满足条件
    
    for(int i=1;i<=9;i++)
    {
        if(!st[i])
        {
            st[i] = true;
            dfs_c(u+1,a,c * 10 + i);//注意:第二个参数要求出c的具体大小
            st[i] = false;
        }
    }
}

void dfs_a(int u,int a) //u表示已经使用了多少数字,a表示当前a的大小
{
    if(a >= n) return;//递归出口
    if(a) dfs_c(u,a,0);//若a不为0,就枚举一下c
    
    for(int i=1;i<=9;i++)
    {
        if(!st[i])
        {
            st[i] = true;
            dfs_a(u+1,a*10+i);//注意:第二个参数要求出a的具体大小
            st[i] = false;//涉及回溯,必须恢复现场
        }
    }
}
int main()
{
    cin>>n;
    dfs_a(0,0);//a必须从0开始,若从1开始,没有标记已使用
    cout<<ans<<endl;
    return 0;
}

95. 费解的开关

image

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

using namespace std;
const int N = 6;
int T;
char g[N][N];
char backup[N][N];
int dx[5] = { 0,-1,1,0,0 };
int dy[5] = { 0,0,0,-1,1 };
void turn(int x, int y)
{
    for (int i = 0; i < 5; i++)
    {
        int a = x + dx[i];
        int b = y + dy[i];
        if (a < 0 || a >= 5 || b < 0 || b >= 5) continue;
        if (backup[a][b] == '1') backup[a][b] = '0';
        else backup[a][b] = '1';
    }
}
int main()
{
    cin >> T;
    while (T--)
    {
        int ans = 10;
        for (int i = 0; i < 5; i++)
        {
            cin >> g[i];
        }
        for (int i = 0; i < 32; i++)//以位运算方式枚举第一行操作的所有方案
        {
            int cnt = 0;
            memcpy(backup, g, sizeof g);//先备份,对backup操作
            for (int j = 0; j < 5; j++)//获取每一位,是1为操作开关,否则不操作开关
            {
                if ((i >> j) & 1 == 1)
                {
                    cnt++;
                    turn(0, j);
                }
            }
            for (int x = 0; x < 4; x++) //每一行开关的操作由前一行状态唯一确定
            {
                for (int y = 0; y < 5; y++)
                {
                    if (backup[x][y] == '0')
                    {
                        cnt++;
                        turn(x + 1, y);
                    }
                }
            }
            bool f = true;
            for (int y = 0; y < 5; y++) //最后判断最后一行是否全亮,若没有,则说明此方案不可取
            {
                if (backup[4][y] == '0')
                {
                    f = false;
                    break;
                }
            }
            if (f) ans = min(ans, cnt); //方案可取,则进行比较,选择操作次数最小的
        }
        if (ans > 6) ans = -1;//若最小次数都大于6,则说明无解
        cout << ans << endl;
    }
    return 0;
}

116. 飞行员兄弟

image

1.位运算枚举法

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

using namespace std;
typedef pair<int, int> PII;
vector<PII>tmp,res;
const int N = 5;

char g[N][N],backup[N][N];
void turn(int x,int y)
{
    for(int i=0;i<4;i++)
    {
        if(backup[x][i] == '+') backup[x][i] = '-';
        else backup[x][i] = '+';
        if(backup[i][y] == '+') backup[i][y] = '-';
        else backup[i][y] = '+';
    }
    if(backup[x][y] == '+') backup[x][y] = '-';
    else backup[x][y] = '+';
    return;
}
int main()
{
    for (int i = 0; i < 4; i ++ )
    {
        cin>>g[i];
    }
    for(int op = 0;op< 1<<16;op++)
    {
        vector<PII>tmp;
        memcpy(backup,g,sizeof g);
        for(int i=0;i<16;i++)
        {
            if(op>>i & 1 == 1)
            {
                int x = i/4;
                int y = i%4;
                tmp.push_back({x,y});
                turn(x,y);
            }
        }
        bool f = true;
        for(int i=0;i<4;i++)
        {
            for(int j=0;j<4;j++)
            {
                if(backup[i][j] == '+')
                {
                    f = false;
                    break;
                }
            }
            if(!f) break;
        }
        if(f)
        {
            if(res.empty() || tmp.size() < res.size()) res = tmp;
        }
    }
    int len = res.size();
    cout<<len<<endl;
    for(auto t:res)
    {
        cout<<t.first + 1<<" "<<t.second + 1<<endl;
    }
    return 0;
}

2.dfs枚举法

#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
char g[5][5];
typedef pair<int,int>PII;
vector<PII>tmp,res;
void turn(int x,int y)
{
    for(int i=0;i<4;i++)
    {
        if(g[x][i] == '+') g[x][i] = '-';
        else g[x][i] = '+';
    }
    for(int i=0;i<4;i++)
    {
        if(g[i][y] == '+') g[i][y] = '-';
        else g[i][y] = '+';
    }
    if(g[x][y] == '+') g[x][y] = '-'; //x.y处开关操作3次等于操作1次
    else g[x][y] = '+';
    return;
}
void dfs(int x,int y)
{
    if(x == 3 && y == 4)//递归出口:枚举完所有开关
    {
        bool f = true;
        for(int i=0;i<4;i++) //检查所有开关是否为开,否则说明此方案不可行
        {
            for(int j=0;j<4;j++)
            {
                if(g[i][j] == '+')
                {
                    f = false;
                    break;
                }
                if(!f) break;
            }
        }
        if(f)//若是,则进行比较,选择操作次数较小的
        {
            if(res.empty()||tmp.size() < res.size())
            {
                res = tmp;
            }
        }
        return;
    }
    if(y==4)//换行
    {
        y = 0;
        x++;
    }
    turn(x,y);
    tmp.push_back({x,y});
    dfs(x,y+1);//选择操作此开关
    
    turn(x,y);//恢复现场
    tmp.pop_back();
    dfs(x,y+1);//选择不操作此开关
}
int main()
{
    for(int i=0;i<4;i++) cin>>g[i];
    dfs(0,0);
    int len = res.size();
    cout<<len<<endl;
    for(int i=0;i<len;i++)
    {
        cout<<res[i].first + 1<<" "<<res[i].second + 1<<endl;
    }
    return 0;
}

标签:递归,int,backup,dfs,st,蓝桥,++,include,递推
来源: https://www.cnblogs.com/zjq182/p/15760836.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有