一、Problem
给出4个小于10个正整数,你可以使用加减乘除4种运算以及括号把这4个数连接起来得到一个表达式。现在的问题是,是否存在一种方式使得得到的表达式的结果等于24。
这里加减乘除以及括号的运算结果和运算的优先级跟我们平常的定义一致(这里的除法定义是实数除法)。
比如,对于 5,5,5,1,我们知道 5 * (5 – 1 / 5) = 24,因此可以得到 24。又比如,对于 1,1,4,2,我们怎么都不能得到24。
输入
输入数据包括多行,每行给出一组测试数据,包括4个小于10个正整数。最后一组测试数据中包括4个0,表示输入的结束,这组数据不用处理。
输出
对于每一组测试数据,输出一行,如果可以得到24,输出“YES”;否则,输出“NO”。
样例输入
5 5 5 1
1 1 4 2
0 0 0 0
样例输出
YES
NO
二、Solution
方法一:回溯
- 先用一种运算符将数耗尽,然后回溯到上一种运算,选择下一种运算,重复上述过程。
- 当某一次深搜完以后,需要恢复状态。
import java.util.*;
import java.math.*;
import java.io.*;
public class Main{
static boolean done;
static double[] a;
static double INF = -1e6 * 1.0;
final static int N = 4;
static double ops(double a, double b, double k) {
if (k == 0) return a + b;
else if (k == 1) return a - b;
else if (k == 2) return a * b;
else return a / b;
}
static void dfs(int x) {
if (done)
return;
Arrays.sort(a);
if (x == N-1) {
if (Math.abs(a[N-1] - 24) < 0.00001)
done = true;
return;
}
double[] t = Arrays.copyOf(a, a.length);
for (int i = x; i < N; i++)
for (int j = x; j < N; j++) {
if (i == j)
continue;
for (int k = 0; k < N; k++) {
a[i] = ops(a[i], a[j], k);
a[j] = INF;
dfs(x+1);
a = Arrays.copyOf(t, t.length);;
}
}
}
public static void main(String[] args) throws IOException {
Scanner sc = new Scanner(new BufferedInputStream(System.in));
BufferedWriter w = new BufferedWriter(new OutputStreamWriter(System.out));
while (true) {
a = new double[N];
for (int i = 0; i < a.length; i++) {
a[i] = sc.nextDouble();
}
if (a[0] == 0 && a[1] == 0 && a[2] == 0 && a[3] == 0)
return;
done = false;
dfs(0);
if (done)System.out.println("YES");
else System.out.println("NO");
}
}
}
复杂度分析
- 时间复杂度: ,
- 空间复杂度: ,