Blue Bridge Cup Brushing Questions - Chapter 1 Recursion and Recursion

BaseOn : https://www.acwing.com

1. Recursion and recursion

Recursive implementation of exponential enumeration

java

import java.util.*;

public class Main{
    
    
    static Scanner in = new Scanner(System.in);		// 输入
    // 看题目范围 n是1到15,我们稍微把数组开大一点点、防止数组越界。
    static int max = 20,n;							
    // 判断每一位是否被用过
    static boolean[] st = new boolean[max];
    public static void main(String[] args){
    
    
        n = in.nextInt();
        dfs(0);
    }
    // dfs(深度优先搜索)
    private static void dfs(int u){
    
    
        // 搜索到最后一位
        if(u == n){
    
    
            // 打印输出
            for(int i = 0;i < n;i++){
    
    
                if(st[i]) System.out.printf("%d ",i+1);
            }
            System.out.println();
            return;
        }
        // 要第u位
        st[u] = true;
        dfs(u+1);
        // 不要第u位
        st[u] = false;
        dfs(u+1);
    }
}

C/C++

#include <bits/stdc++.h>

using namespace std;

const int N = 20;

bool st[N];

int n;

void dfs(int u){
    
    
    // 递归到了叶子节点
    if(u == n){
    
    
        for(int i = 0;i < n;i++){
    
    
            if(st[i]) cout << i + 1 << " ";
        }
        cout << endl;   // 换行
        return;
    }
    // 选
    st[u] = true;
    dfs(u+1);
    
    // 不选
    st[u] = false;
    dfs(u+1);
}

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

insert image description here

Recursive implementation of permutation enumeration

Java

import java.util.*;
import java.io.*;
public class Main {
    
    
    static Scanner in = new Scanner(System.in);
    static int max = 10, n;
    static int[] path = new int[max];       // 存储路径
    static boolean[] st = new boolean[max]; // 记录每个数字是否被使用了
    static BufferedWriter out = new BufferedWriter(new OutputStreamWriter(System.out));
    public static void main(String[] args)throws Exception{
    
    
        n = in.nextInt();
        dfs(0);
        out.flush();
    }
    private static void dfs(int u) throws Exception{
    
    
        if(u == n){
    
    
            for(int i = 0;i < n;i++) out.write(path[i] + " ");	// 快速写出
            out.write("\n");       // 换行
            return;
        }
        for(int i = 0;i < n;i++){
    
    
            if(!st[i]){
    
    
                st[i] = true;
                path[u] = i+1;
                dfs(u+1);
                st[i] = false;
                path[u] = 0;
            }
        }
    }
}

C/C++

#include <bits/stdc++.h>

using namespace std;

const int N = 10;

int path[N];
bool st[N];
int n;

void dfs(int u){
    
    
    if(u == n){
    
    
        for(int i = 0;i < n;i++) cout << path[i] << " ";
        cout << endl;
        return;
    }
    for(int i = 0;i < n;i++){
    
    
        if(!st[i]){
    
    
            st[i] = true;
            path[u] = i+1;
            dfs(u+1);
            st[i] = false;
        }
    }
}

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

Recursive implementation of composite enumeration

Java

import java.util.*;
public class Main{
    
    
    static Scanner in = new Scanner(System.in);
    static int max = 30,n,m;
    static int[] path = new int[max];
    public static void main(String[] args){
    
    
        n = in.nextInt();
        m = in.nextInt();
        dfs(0);
        return;
    }
    public static void dfs(int u){
    
    
        if(u == m){
    
    
            for(int i = 0;i < m;i++) System.out.printf("%d ",path[i]);
            System.out.println();
            return;
        }
        for(int i = 1;i <= n;i++){
    
    
            if(u == 0) path[u] = i;
            else {
    
    
                if(path[u-1] < i) path[u] = i;
                else continue;
            }
            dfs(u+1);
        }
    }
}

C/C++

#include <bits/stdc++.h>

using namespace std;

const int N = 30;

int path[N];

int n,m;

void dfs(int u){
    
    
    if(u == m){
    
    
        for(int i = 0;i < m;i++) cout << path[i] << " ";
        cout << endl;
        return;
    }
    for(int i = 1;i <= n;i++){
    
    
        if(u == 0) path[u] = i;
        else{
    
    
            // 前一位要比这一位小
            if(path[u-1] < i) path[u] = i;
            else continue;
        }
        dfs(u+1);
    }
}

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

Simple Fibonacci Sequence

java

import java.util.*;
public class Main{
    
    
    static Scanner in = new Scanner(System.in);
    static int n,a = 0,b  = 1;
    public static void main(String[] args){
    
    
        n = in.nextInt();
        for(int i = 0;i < n;i++){
    
    
            System.out.printf("%d ",a);
            int temp = a + b;
            a = b;
            b = temp;
        }
    }
}

C/C++

#include <bits/stdc++.h>

using namespace std;

// 递推公式
// a[i] = a[i-1] + a[i-2]

int n;

int main(){
    
    
    int a = 0,b = 1;
    cin >> n;
    for(int i = 0;i < n;i++){
    
    
        cout << a << " ";
        int temp = a + b;
        b = a;
        a = temp;
    }
    cout << endl;
    return 0;
}

inexplicable switch

To write this topic, we must first analyze a few points:

  1. Each light bulb can only be pressed once, because pressing twice will not change anything, and there are more steps
  2. It doesn't matter what order you press, it doesn't matter which one you press first and which one you press next.

Relying on the above two conclusions, let's look at this question:

  1. We can only look at the first line first, and we can press the first line at will, but each light bulb can only be operated once.
  2. The first line has been manipulated, and it is the turn of the second line. If the first line is still extinguished, it can only be extinguished through the second line. The logic is like this. Whether the bulbs in each row below operate depends on the status of the bulbs in the previous row.

therefore:

  1. We enumerate all the states in the first row
    1. How to enumerate, there are a total of 5 light bulbs in the first line, each light bulb has two states of on or off, then there are 2^5=32 states
  2. Then operate the subsequent rows according to the current state of the first row
  3. Go to the last line to see if there is any open, if there is, it means that it cannot be completely extinguished

C/C++

#include <bits/stdc++.h>

using namespace std;

const int N = 6;

char g[N][N],backup[N][N];

// 偏移量,用于遍历(x,y)的上下左右中
int dx[5] = {
    
    1,0,-1,0,0},dy[5] = {
    
    0,1,0,-1,0};

// 将(x,y)的上下左右摁一遍
void turn(int x,int y){
    
    
    for(int i = 0;i < 5;i++){
    
    
        int nx = x + dx[i],ny = y + dy[i];
        if(nx < 0 || nx > 5 || ny < 0 || ny > 5) continue;  // 外界不需要考虑
        if(g[nx][ny] == '0') g[nx][ny] = '1';
        else g[nx][ny] = '0';
    }
}

int main(){
    
    
    int T;
    cin >> T;
    while(T--){
    
    
        // 将图读入
        for(int i = 0;i < 5;i++) cin >> g[i];
        // 第一行一共5个按钮,每个按钮开或不开一共2种情况,2^5 = 32
        int ans = 10;
        for(int op = 0;op < 32;op++){
    
    
            memcpy(backup,g,sizeof g);  // 将 g的内容放入backup中备份
            int step = 0;   // 操作的步数
            // 第一行所有情况
            for(int i = 0;i < 5;i++){
    
    
                // 当前对应了1就操作
                if(op >> i & 1){
    
    
                    step++;
                    turn(0,i);
                }
            }
            // 每一行的每一个开关开或不开其实是受上一行的开关影响的
            for(int i = 0;i < 4;i++){
    
    
                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) ans = min(ans,step);
            memcpy(g,backup,sizeof g);  // 将 g的内容放入backup中备份
        }
        if(ans > 6) ans = -1;
        cout << ans << endl;
    }
    return 0;
}

java

import java.util.*;
public class Main{
    
    
    static Scanner in = new Scanner(System.in);
    static int max = 5;
    static char[][] g = new char[max][max];
    static char[][] backup = new char[max][max];
    static int[] dx = {
    
    1,0,-1,0,0},dy = {
    
    0,1,0,-1,0};
    public static void main(String[] args){
    
    
        int T = in.nextInt();
        // T个测试样例
        while(T-- > 0){
    
    
            // 读入图
            int res = 10;
            for(int i = 0;i < 5;i++) g[i] = in.next().toCharArray();
            // 要对图进行一次备份
            for(int i = 0;i < 5;i++){
    
    
                for(int j = 0;j < 5;j++) backup[i][j] = g[i][j];
            }
            // 第一行有5个格子,每个格子开或关有2种可能,一共2^5=32种,我们这里采用二进制来表示
            for(int op = 0;op < 32;op++){
    
    
                int step = 0;
                // 先操作第一行
                for(int i = 0;i < 5;i++){
    
    
                    // 当前位是1就进行一次操作
                    if((op >> i & 1) == 1){
    
    
                        turn(0,i);
                        step++;
                    }
                }
                // 通过上一行操作下一行
                for(int i = 0;i < 4;i++){
    
    
                    for(int j = 0;j < 5;j++){
    
    
                        // 当前是灭的,那么下一行对应的就要开
                        if(g[i][j] == '0'){
    
    
                            turn(i+1,j);
                            step++;
                        }
                    }
                }
                // 判断最后一行有没有灭的
                boolean dark = false;
                for(int i = 0;i < 5;i++){
    
    
                    if(g[4][i] == '0'){
    
    
                        dark = true;
                        break;
                    }
                }
                
                // 全灭的话
                if(!dark) res = Math.min(res,step);
                // 对图进行还原
                for(int i = 0;i < 5;i++){
    
    
                    for(int j = 0;j < 5;j++)  g[i][j] = backup[i][j];
                }
            }
            // 超过步数
            if(res > 6) res = -1;
            // 此时已经遍历了32种情况
            System.out.println(res);
        }
    }
    public static void turn(int x,int y){
    
    
        for(int i = 0;i < 5;i++){
    
    
            int nx = x + dx[i],ny = y + dy[i];
            if(nx < 0 || nx >= 5 || ny < 0 || ny >= 5) continue;    // 出界不需要考虑
            if(g[nx][ny] == '0') g[nx][ny] = '1';
            else g[nx][ny] = '0';
        }
    }
}

coin flip

According to the previous thinking:

  1. Each coin will only be actively flipped once (because the flip next to it is not actively flipped)
  2. The order of flipping does not matter

For this question:

​ We can enumerate from left to right. If the current corresponding bit is different, just flip it.

c/c++

#include <bits/stdc++.h>

using namespace std;

string a,b;

int ans = 0;

int main(){
    
    
    cin >> a >> b;
    int n = a.length();
    for(int i = 0;i < n - 1;i++){
    
    
        // 当前字符不相等,就要翻转,
        // 翻转后一定相等,就不用判断了
        // 但是只要翻转了,下一个字符就一定会改
        if(a[i] != b[i]){
    
    
            ans++;
            if(a[i+1] == '*') a[i+1] = 'o';
            else a[i+1] = '*';
        }
    }
    cout << ans << endl;
}

Java

import java.util.*;
import java.io.*;
public class Main{
    
    
    static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
    static int N = 110;
    static char[] begin = new char[N],end = new char[N];
    public static void main(String[] args)throws Exception{
    
    
        int ans = 0;
        // 读入
        String a = in.readLine();
        String b = in.readLine();
        begin = a.toCharArray();
        end = b.toCharArray();
        for(int i = 0;i < begin.length-1;i++){
    
    
            if(begin[i] != end[i]){
    
    
                if(begin[i+1] == '*') begin[i+1] = 'o';
                else begin[i+1] = '*';
                ans++;
            }
        }
        in.close();
        System.out.println(ans);
    }
}

pilot brother

C/C++

#include <bits/stdc++.h>

#define x first
#define y second

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] = '-';
}

// 将x行,y列的所有操作一遍
void turn_all(int x,int y){
    
    
    for(int i = 0;i < 4;i++){
    
    
        turn_one(i,y);
        turn_one(x,i);
    }
    // 上面导致(x,y)改变了两次,抵消了
    turn_one(x,y);
}

int main(){
    
    
    // 读入图
    for(int i = 0;i < 5;i++) cin >> g[i];
    vector<PII> ans;
    // 枚举所有的情况
    for(int op = 0;op < 1 << 16;op++){
    
    
        memcpy(backup,g,sizeof g);  // 备份
        // 这一种情况的操作
        vector<PII> temp;
        // 对每一个点继续操作
        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){
    
    
            // ans为空或者ans的操作步骤比temp多
            if(ans.empty() || ans.size() > temp.size()) ans = temp;
        }
        memcpy(g,backup,sizeof g);  // 还原
    }
    // 输出
    cout << ans.size() << endl;
    for(auto op : ans){
    
    
        cout << op.x + 1 << " " << op.y+1 << endl;
    }
    return 0;
}

Java

import java.util.*;
public class Main{
    
    
    static int N = 4;
    static char[][] g = new char[N][N],backup = new char[N][N];
    static Scanner in = new Scanner(System.in);
    static List<int[]> ans = new ArrayList<>();
    public static void main(String[] args){
    
    
        // 把图给读进来
        for(int i = 0;i < 4;i++) g[i] = in.next().toCharArray();
        // 一共16个开关,全部枚举,2^16
        for(int op = 0;op < (1 << 16);op++){
    
    
            List<int[]> temp = new ArrayList<>();
            // 备份图
            for(int i = 0;i < 4;i++){
    
    
                for(int j = 0;j < 4;j++){
    
    
                    backup[i][j] = g[i][j];
                }
            }
            // 遍历每一个点
            for(int i = 0;i < 4;i++){
    
    
                for(int j = 0;j < 4;j++){
    
    
                    // 为1就是要操作
                    if(((op >> get(i,j)) & 1) == 1){
    
    
                        turn_all(i,j);
                        temp.add(new int[]{
    
    i,j});
                    }
                }
            }
            // 此时遍历完了,看是否全打开了
            boolean 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){
    
    
                if(ans.isEmpty() || ans.size() > temp.size() ) ans = temp;
            }
            // 复原
            for(int i = 0;i < 4;i++){
    
    
                for(int j = 0;j < 4;j++){
    
    
                    g[i][j] = backup[i][j];
                }
            }
        }
        System.out.println(ans.size());
        for(int[] res : ans){
    
    
            System.out.printf("%d %d\n",res[0]+1,res[1]+1);
        }
    }
    public static int get(int x,int y){
    
    
        return 4 * x + y;
    }
    public static 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);
    }
    public static void turn_one(int x,int y){
    
    
        if(g[x][y] == '-') g[x][y] = '+';
        else g[x][y] = '-';
    }
}

with score

Idea one:

  1. Formalize with fractions as: n = a + b / c
    1. Where a, b, c are the combination of 1~9
  2. Simplified again is n * c = a * c + b
    1. So we only need to enumerate all a, b, c
    2. It is enough to make the above equation hold
  3. How to enumerate all a, b, c?
    1. Through the previous recursion, the permutation enumeration can be realized, and it can also be fully permuted.

C/C++

#include <bits/stdc++.h>

using namespace std;

const int N = 10;

int path[N];
bool st[N];

int n,ans = 0;

// 计算path[l,r]的位数和
int cala(int l,int r){
    
    
    int sum = 0;
    for(int i = l; i <= r;i++){
    
    
        sum *= 10;
        sum += path[i];
    }
    return sum;
}

void dfs(int u){
    
    
    if(u == N){
    
    
        // 此时path中存了1~9的全排列
        for(int i = 1;i <= 7;i++){
    
    
            for(int j = i+1;j <= 8;j++){
    
    
                int a = cala(1,i);
                int b = cala(i+1,j);
                int c = cala(j+1,9);
                if(n*c == a * c + b) ans++;
            }
        }
    }
    for(int i = 1;i < N;i++){
    
    
        if(!st[i]){
    
    
            st[i] = true;
            path[u] = i;
            dfs(u+1);
            st[i] = false;
        }
    }
}

int main(){
    
    
    cin >> n;
    dfs(1);
    cout << ans << endl;
    return 0;
}

JAVA

import java.util.*;
public class Main{
    
    
    static int N = 10;
    static int[] path = new int[N];         // 用于储存全排列
    static boolean[] st = new boolean[N];
    static Scanner in = new Scanner(System.in);
    static int n,ans = 0;
    public static void main(String[] args){
    
    
        n = in.nextInt();
        dfs(1);
        System.out.println(ans);
    }
    private static void dfs(int u){
    
    
        // 此时path以及存好了全排列
        if(u == N){
    
    
            for(int i = 1;i <= 7;i++){
    
    
                for(int j = i+1;j <= 8;j++){
    
    
                    int a = cala(1,i);
                    int b = cala(i+1,j);
                    int c = cala(j+1,9);
                    if(n*c == a*c + b) ans++;
                }
            }
        }
        for(int i = 1;i < N ;i++){
    
    
            if(!st[i]){
    
    
                path[u] = i;
                st[i] = true;
                dfs(u+1);
                st[i] = false;
            }
        }
    }
    public static int cala(int l,int r){
    
    
        int sum = 0;
        for(int i = l;i <= r;i++){
    
    
            sum *= 10;
            sum += path[i];
        }
        return sum;
    }
}

Idea 2:

  1. According to the above, n * c = a * c + b
    1. There are three position numbers in the equation, you only need to know two of them
    2. Then we enumerate a and c to get b
    3. Determine whether b meets the requirements, if it meets the requirements

c/c++

#include <bits/stdc++.h>

using namespace std;

const int N = 20;

bool st[N],backup[N];

int n,ans;

// 判断等式是否成立
bool check(int a,int c){
    
    
    int b = n*c - a*c;
    // a b c 都得是非0的
    if(!a || !b || !c) return false;
    // st表在递归中还要使用,使用备份表
    memcpy(backup,st,sizeof st);
    // 判断b的每一位有没有和a、c有重合的
    while(b){
    
    
        int x = b % 10;
        b /= 10;
        // 出现位0或者重复使用过
        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;
        }
    }
}

// 从第u位枚举,此时的a大小位a
void dfs_a(int u,int a){
    
    
    // 第10位
    if(u == 9) return;
    // 剪枝,因为 n = a + b/c 所有a肯定小于n
    if(a > n) return;
    // 递归枚举c
    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;
}

Java

import java.util.*;
public class Main{
    
    
    static int N = 10;
    static boolean[] st = new boolean[N];       // 每一位只能使用一次
    static Scanner in = new Scanner(System.in);
    static int n,ans = 0;
    public static void main(String[] args){
    
    
        n = in.nextInt();
        // 从1开始搜索,此时a为0
        dfs_a(1,0);
        System.out.println(ans);
    }
    private static void dfs_a(int u,int a){
    
    
        // 第十位
        if(u == N) return;
        // 剪枝,a不可能大于n
        if(a > n) return;
        // 递归遍历c
        if(a > 0) dfs_c(u,a,0);
        for(int i = 1;i < N;i++){
    
    
            if(!st[i]){
    
    
                st[i] = true;
                // 递归a
                dfs_a(u+1,a*10+i);
                st[i] = false;
            }
        }
    }
    private static void dfs_c(int u,int a,int c){
    
    
        if(u == N) return;
        // 判断此时的ac是否满足条件
        if(check(a,c)) ans++;
        for(int i = 1;i < N;i++){
    
    
            if(!st[i]){
    
    
                st[i] = true;
                // 递归c
                dfs_c(u+1,a,c*10+i);
                st[i] = false;
            }
        }
    }
    
    // 判断是否满足条件
    private static boolean check(int a,int c){
    
    
        int b = n * c - a * c;
        // a b c 都是正数
        if(b <= 0 || a <= 0 || c <= 0) return false;
        // 判断是否有重复使用的数
        boolean[] backup = new boolean[N];
        // 使用备份来判断
        for(int i = 1;i < N;i++) backup[i] = st[i];
        while(b > 0){
    
    
            int x = b %10;
            b /= 10;
            if(x == 0 || backup[x]) return false;
            backup[x] = true;
        }
        // 判断1~9是否每一位都使用过
        for(int i = 1;i < N;i++){
    
    
            if(!backup[i]) return false;
        }
        return true;
    }
    
}

Guess you like

Origin blog.csdn.net/Destiny_159/article/details/121825948