蓝桥杯--递归1

备战蓝桥杯 谨以此记录历程

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

原题链接

输出n个数字的各种组合,乱序即可

思路有多种,自认为最简单思路从1进行dfs,仅传参一个元素就可,枚举至n,分别考虑当前元素是否输出两种情况,输出则存入容器,进行下一元素的判断,直至最后一个元素遍历容器输出。第一种情况dfs结束后容器回溯,再进行不输出当前情况dfs。
考虑到容器需要进行回溯且不需排序,可以使用vector容器,由于vector容器底层仍使用数组,回溯时可以利用size来删除末尾元素达到回溯效果。也可以直接使用数组,需要定义末尾指针来控制删除末尾元素。

import java.io.*;
import java.util.*;


public class Main {
    
    
	static Scanner tab = new Scanner(System.in);
	static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
	static BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
	static int N = 100010;
	
	static int n;
	static Vector<Integer> v=new Vector<Integer>();
	
	static public void dfs(int t) {
    
    
		if(t>n) {
    
    
			for(int i=0;i<v.size();i++) {
    
    
				System.out.print(v.get(i)+" ");
			}
			System.out.println();
			return ;
		}
		v.add(t);
		dfs(t+1);
		v.remove(v.size()-1);
		dfs(t+1);
	}
	
	public static void main(String[] args) throws IOException {
    
    
		n=tab.nextInt();
		dfs(1);
		
	}
}


另一种方式是直接使用一个boolean数组记录各数字是否输出,也是y总的做法,与上述方法基本类似,只是改变了输出方式。


import java.io.*;
import java.util.*;


public class Main {
    
    
	static Scanner tab = new Scanner(System.in);
	static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
	static BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
	static int N = 100010;
	
	static boolean st[]=new boolean[N];
	static int n;
	
	static public void dfs(int t) {
    
    
		if(t>n) {
    
    
			for(int i=1;i<=n;i++) {
    
    
				if(st[i]) {
    
    
					System.out.print(i+" ");
				}
			}
			System.out.println();
			return ;
		}
		dfs(t+1);
		st[t]=true;
		dfs(t+1);
		st[t]=false;
	}
	
	public static void main(String[] args) throws IOException {
    
    
		n=tab.nextInt();
		dfs(1);
		
	}
}


AcWing 94. 递归实现排列型枚举

原题链接

从1至n输出所有数量为n的全排列组合,字典升序

常规递归做法,以位数传参,vis标记是否使用当前数字,未使用则对两种情况分别递归及回溯递归,递归至最后一位进行输出即可。

import java.io.*;
import java.util.*;


public class Main {
    
    
	static Scanner tab = new Scanner(System.in);
	static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
	static BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
	static int N = 100010;
	
	static boolean vis[]=new boolean[N];
	static int a[]=new int [N];
	static int n;
	
	static public void dfs(int t) {
    
    
		if(t>n) {
    
    
			for(int i=1;i<=n;i++) {
    
    
				System.out.print(a[i]+" ");
			}
			System.out.println();
			return ;
		}
		for(int i=1;i<=n;i++) {
    
    
			if(!vis[i]) {
    
    
				vis[i]=true;
				a[t]=i;
				dfs(t+1);
				vis[i]=false;
			}
		}
		
	}
	
	public static void main(String[] args) throws IOException {
    
    
		n=tab.nextInt();
		dfs(1);
		
	}
}


AcWing 95. 费解的开关

原题链接

给出一个5*5的01矩阵,每调整一个数字会导致以它的位置为中心的小十字范围内数字改变为0或1,求能否在6步之内调整为矩阵全1。

这题感觉和递归关联不大,不过暴力的话肯定会超时,需要简化。由于每一个坐标(x,y)的下方(x+1,y)可以改变当前位置(x,y)的值,且不影响x行的其他数字,因此当确定第一行的状态后,可以从第一行开始处理,每当遇0则对它的下方进行调整,直至第四行,第五行的状态即唯一。将第一行的全部调整情况枚举出来,每个位置两种状态,即是2^5–32种情况,求出32种方案的最小值,判断即可。

import java.io.*;
import java.util.*;


public class Main {
    
    
	static Scanner tab = new Scanner(System.in);
	static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
	static BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
	static int N = 100010;
	
	static int bg[][]=new int [20][20];
	static int g[][]=new int [20][20];
	
	public static void turn(int x, int y) {
    
    
		int[] dx = new int[] {
    
     0, -1, 0, 1, 0 };
		int[] dy = new int[] {
    
     -1, 0, 1, 0, 0 };
		for (int i = 0; i < 5; i++) {
    
    
			int xx = x + dx[i];
			int yy = y + dy[i];
			if (xx >= 0 && xx < 5 && yy >=0 && yy < 5) {
    
    
				g[xx][yy] ^= 1;
			}
		}
	}
	
	public static void main(String[] args) throws IOException {
    
    
		int n=tab.nextInt();
		while(n-->0) {
    
    
			int res=10;
			for(int i=0;i<5;i++) {
    
    
				String s=tab.next();
				for(int j=0;j<5;j++) {
    
    
					bg[i][j]=s.charAt(j)-'0';
				}
			}
			for(int op=0;op<1<<5;op++) {
    
    
				int cnt=0;
				for(int i=0;i<5;i++) {
    
    
					for(int j=0;j<5;j++) {
    
    
						g[i][j]=bg[i][j];
					}
				}
				for(int i=0;i<5;i++) {
    
    
					if((op>>i&1)==1) {
    
    
						turn(0, i);
						cnt++;
					}
				}
				for(int i=0;i<4;i++) {
    
    
					for(int j=0;j<5;j++) {
    
    
						if(g[i][j]==0) {
    
    
							turn(i+1, j);
							cnt++;
						}
					}
				}
				
				boolean flag=true;
				for(int i=0;i<5;i++) {
    
    
					if(g[4][i]==0) {
    
    
						flag=false;
						break;
					}
				}
				if(flag) {
    
    
					res=Math.min(res, cnt);
				}
			}
			if(res<=6) {
    
    
				System.out.println(res);
			}
			else
				System.out.println("-1");
		
		}
	}
}


这题开始接触到了位运算,1<<5则是二进制的将1从最右端左移5位,也就是100000,相当于2^5=32。

在此题中op的32种二进制形式正好对应第一行的32种情况,如当op=17时,八位二进制表达为00010001,当i=3时,op>>i则是将op右移3位即00000010,取最低位则op>>i=2。

按位与运算 &:op>>i&1则是先将op右移后的得数x与1进行按位与运算,当x的最低位和1的最低位相同------都为1时,才会返回1,否则都会返回0。由于java的判断语句括号中只能判断boolean值,因此后面加上==1来判断。

这里实现的效果是op二进制数从左至右第i位是否为1,如为1则调整该位置,方便后续的处理。

异或运算 ^:
1^1=0
0^0=0
1^0=1
0^1=1
x^=1 也就是 x=x^1,实现的效果即是将x在01间进行调换,简化判断。异或运算运用比较复杂,可以参照leetcode 只出现一次的数字


314还搁这敲代码:)

猜你喜欢

转载自blog.csdn.net/ooold_six/article/details/114752480