蓝桥杯
我的AcWing
题目及图片来自蓝桥杯C++ AB组辅导课
递归
利用递归+dfs枚举全排列
递归搜索树
每一个递归问题都可以画成递归搜索树求解。
例题
高中数学集合问题
思想:考虑选不选这个数。
import java.util.Scanner;
public class Main {
static int n, N = 16;
static int[] st = new int[N];
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
dfs(1);
}
private static void dfs(int u) {
if (u > n) {
for (int i = 1; i <= n; i++) {
if (st[i] == 1) {
System.out.print(i + " ");
}
}
System.out.println();
return;
}
st[u] = 2;
dfs(u + 1);
st[u] = 0;
st[u] = 1;
dfs(u + 1);
st[u] = 0;
}
}
高中数学枚举 ,输出n个数所有排列的次序。
题中说按字典序排列,但我们枚举后搜索树已经是按照字典序排列了。
思想:
- 依次枚举每个数放到哪个位置
- 依次枚举每个位置放那个数(本题代码)
import java.util.Scanner;
public class Main {
static int n, N = 10;
static int[] state = new int[N];
static boolean[] used = new boolean[N];
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
dfs(1);
}
private static void dfs(int u) {
if (u > n) {
for (int i = 1; i <= n; i++) {
System.out.print(state[i] + " ");
}
System.out.println();
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;
}
}
}
}
1~5选3个数,升序排列
思想:组合型枚举就是把指数型符合长度的结果挑出来。
优化:剪枝 ,优化dfs,假如第一个数是4,那么只有5可以选,凑不成3个数,第一个数是5也同理,所以第一个数不需要考虑4和5的分支。
import java.util.Scanner;
public class Main {
static int n, m, N = 26;
static Scanner sc = new Scanner(System.in);
static int[] way = new int[N];
public static void main(String[] args) {
n = sc.nextInt();
m = sc.nextInt();
dfs(1, 1);
}
private static void dfs(int u, int start) {
if (u + n - start < m) return;
if (u == m + 1) {
for (int i = 1; i <= m; i++) {
System.out.print(way[i] + " ");
}
System.out.println();
return;
}
for (int i = start; i <= n; i++) {
way[u] = i;
dfs(u + 1, i + 1);
way[u] = 0;
}
}
}
第四届2013年蓝桥杯真题
JavaB组第9题
同样暴力枚举 n = a + b / c ,两边同时乘c,c·n = c·a + b ,n已知,枚举a,b,c即可求解。
import java.util.Scanner;
public class Main {
static final int N = 10;
static int n;
static int cnt;
static int[] num = new int[N];
static boolean[] used = new boolean[N];
static Scanner sc = new Scanner(System.in);
public static void main(String[] args) {
n = sc.nextInt();
dfs(0);
System.out.print(cnt);
}
private static void dfs(int u) {
if (u == 9) {
for (int i = 0; i < 7; i++) {
for(int j = i + 1; j < 8; j++) {
int a = calc(0, i);
if (a >= n) return;
int b = calc(i + 1, j);
int c = calc(j + 1, 8);
if (a * c + b == c * n) {
cnt++;
}
}
}
return;
}
for (int i = 1; i <= 9; i++) {
if (!used[i]) {
used[i] = true;
num[u] = i;
dfs(u + 1);
used[i] = false;
}
}
}
private static int calc(int l, int r) {
int res = 0;
for (int i = l; i <= r; i++) {
res = res * 10 + num[i];
}
return res;
}
}
y总的优化方案(很难):其实我们不用枚举b了,当枚举完a和c后,利用公式变换得到b = c·n - c·a 即得到b的值。
import java.util.Scanner;
import java.util.Arrays;
public class Main {
static final int N = 10;
static int n;
static int ans;
static boolean[] st = new boolean[N];
static boolean[] backup = new boolean[N];
static Scanner sc = new Scanner(System.in);
public static void main(String[] args) {
n = sc.nextInt();
dfs_a(0, 0);
System.out.print(ans);
}
private static void dfs_a(int u, int a) {
if (a >= n) return;
if (a != 0) 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;
}
}
}
private static 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;
}
}
}
private static boolean check(int a, int c) {
long b = n * (long)c - a * c;
if (a == 0 || b == 0 || c == 0) return false;
backup = Arrays.copyOf(st, st.length);
while (b != 0) {
int x = (int)(b % 10);
b /= 10;
if (x == 0 || backup[x]) return false;
backup[x] = true;
}
for (int i = 1; i <= 9; i++) {
if (!backup[i]) return false;
}
return true;
}
}
有对代码不理解的地方可以在下方评论。
|