Uva 1354


模拟二叉树的数组形式去暴力,对于天平的每个节点,都可以看做是二叉树的节点,放天平的位置标记为-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;
		}
	}
}


你可能感兴趣的:(暴力,回溯法,Uva)