模拟二叉树的数组形式去暴力,对于天平的每个节点,都可以看做是二叉树的节点,放天平的位置标记为-1,放重物的位置标记为重物的序号。当i的父亲节点为-1时,i这个位置就可以选择放天平还是放重物,否则就得跳过。
dfs的过程中,u是当前考虑的节点号,m是当前还有多少个位置可以放,use是还有多少个重物。
放天平的条件是use - m ≥ 1,因为每放一个天平,可悬挂重物的位置就多1,但是位置如果多于重物就肯定有位置没有重物可以挂,不符合平衡的条件;
放重物的条件是m!=1 || use==1,如果放重物后,没有位置放下一个重物的情况是不可以的。
终止条件,use = 0,所有重物都放置完毕。
计算左右边界的方法,因为方案已经确定,所以val[i]代表节点的重量,l[i]代表节点的左伸,r[i]代表节点的右伸,从最后一个节点一直递推到节点1;每个节点的重量,左伸右伸均只和它的孩子节点有关。
import java.text.DecimalFormat;
import java.util.Scanner;
public class Uva_1354 {
static int N = 10;
static int M = 105;
static int n;
static int[] v;
static int[] t;
static double R;
static double[] w = new double[N];
static double ans;
static double[] l = new double[M];
static double[] r = new double[M];
static double[] val = new double[M];
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
DecimalFormat format = new DecimalFormat("0.0000000000000000");
int T = scanner.nextInt();
v = new int[N];
t = new int[M];
while (T-- > 0) {
init(t);
init(v);
t[1] = -1; ans = -1;
R = scanner.nextDouble();
n = scanner.nextInt();
for (int i = 1; i <= n; i++) {
w[i] = scanner.nextDouble();
}
if (n == 1) System.out.println(format.format(0.0));
else {
dfs(2, 2, n);
if (ans == -1) System.out.println(-1);
else System.out.println(format.format(ans));
}
}
}
public static void dfs(int u, int m, int use) {
if (use == 0) {
judge(u -1);
return ;
}
if (t[u/2] != -1) {
dfs(u+1, m, use);
} else {
if (use > m) {
t[u] = -1;
dfs(u+1, m+1, use);
t[u] = 0;
}
if (m == 1 && use > 1) return ;
for (int i = 1; i <= n; i++) if (v[i] == 0) {
v[i] = 1;
t[u] = i;
dfs(u+1, m-1, use-1);
v[i] = 0;
t[u] = 0;
}
}
}
public static void judge(int u) {
init(l);
init(r);
init(val);
for (int i = u; i > 0; i--) {
if (t[i] == -1) {
int x = i * 2, y = i * 2 + 1;
val[i] = val[x] + val[y];
double li = val[y] / val[i];
double ri = val[x] / val[i];
l[i] = Math.min(-li + l[x], ri + l[y]);
r[i] = Math.max(-li + r[x], ri + r[y]);
} else if (t[i] >= 0) val[i] = w[t[i]];
}
double tmp = r[1] - l[1];
if ((tmp - R) < 1e-5 && tmp > ans) ans = tmp;
}
public static void init(double[] a) {
for (int i = 0; i < a.length; i++) {
a[i] = 0;
}
}
public static void init(int[] a) {
for (int i = 0; i < a.length; i++) {
a[i] = 0;
}
}
}