持续更新蓝桥杯算法训练题解,有兴趣可以关注一波呀。
题目是说用4个数字,可以进行加减乘除和括号运算,然后求不超过24的最大数字是多少。
数据量很小,就4个数字,完全可以进行暴力求解。
本来考虑的是:直接使用全排列进行括号的代换,发现这种带有结合的(10 + 1) * (1 + 1),不可能一个接一个的算出来。于时又加上了一个函数dfs(cur),返回一个set,表示从[cur, 4]的所有计算结果,用来表示括号。然后就可以了。
- 这个题目说的如果不能整除,就不能使用除法。让后在没写dfs2的时候,没有考虑,导致出错。错误数据如下:
11
13
11
5
前两个的和是24,如果后两个不能进行除法,默认设置为0,那么答案就是24 + 0 = 24,就会出错。
- 另外如果大于了24,不应该直接返回,因为还有减法和除法,可能会把数值缩小。所以应该最后返回的时候进行判断。
package lanqiao;
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;
/**
* @author: Zekun Fu
* @date: 2022/10/13 14:58
* @Description: 24点
* 1. 第一个是否减去乘以或者加上?
* 2. 除法必须要整除
* 3. 括号可以转化成4个数字的全排列
*
*
*/
public class DianOf24 {
// 24种全排列
private static int[][] b = new int[24][4];
private static int[] a = new int[4];
private static int idx = 0;
private final static char[] opr = {'+', '*', '-', '/'};
private static int id;
public static void generate_permutation(int n,int A[],int cur)
{
if(cur == n){
b[idx++] = Arrays.copyOf(A, n);
}
else for(int i = 1;i <= n;i++){
int ok = 1;
for(int j = 0;j < cur;j++){
if(A[j] == i)ok = 0;
}
if(ok == 1){
A[cur] = i;
generate_permutation(n, A, cur + 1);
}
}
}
private static int cal(int a, int b, char op) {
if (op == '+') return a + b;
if (op == '-') return a - b;
if (op == '*') {
if (a == 0) return b;
return a * b;
}
if (b != 0 && a % b == 0) return a / b;
return 0; // 如果是0代表无法操作
}
private static Set<Integer> dfs2(int cur) {
if (cur == 4) return new HashSet<>();
Set<Integer>child = dfs2(cur + 1);
Set<Integer>ans = new HashSet<>();
for (Integer x: child) {
for (int i = 0; i < 4; i++) {
int y = cal(a[b[id][cur] - 1], x, opr[i]);
if (y != 0) // 如果等于0说明无法操作
ans.add(y);
}
}
if (ans.isEmpty()) ans.add(a[b[id][cur] - 1]);
return ans;
}
private static int dfs(int cur, int total) {
if (cur == 4) {
if (total <= 24) return total;
return 0;
}
int ans = 0;
// 括号运算,直接计算后面值的所有可能性。
Set<Integer>back = dfs2(cur);
for (Integer x : back) {
for (int i = 0; i < 4; i++) {
int calAns = cal(total, x, opr[i]);
if (calAns > 24) continue;
ans = Math.max(ans, calAns);
}
}
// 加减乘除运算
for (int i = 0; i < 4; i++) {
int calAns = cal(total, a[b[id][cur] - 1], opr[i]);
if (calAns == 0) continue; // 不可以整除
ans = Math.max(ans, dfs(cur + 1, calAns));
}
return ans;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
// 生成1-4的全排列
generate_permutation(4, new int[4], 0);
while (n-- != 0) {
for (int i = 0; i < 4; i++) {
a[i] = sc.nextInt();
}
int ans = 0;
for (int i = 0; i < idx; i++) {
id = i;
ans = Math.max(dfs(0, 0), ans);
}
System.out.println(ans);
}
}
}
/*
1
3
3
3
3
*/
/*
1
1
1
1
10
(10 + 1) * (1 + 1): 很明显这种没法表示,也就是说,括号没法计算
如果想要计算,应该加上一个函数:
dfs2(cur) : 返回从cur -> 4的所有可能结果,相当于从这加上了一个括号
或者直接从
total opr dfs()
*/