锯桌腿

package desk;

/**
 * 一张桌子有n个不等长的桌腿,当最常桌腿大于所有桌腿数一半的时候,桌子可以平衡
 * 每锯掉一条腿需要wi的代价,请用最小代价使桌子保持平衡
 * @author Administrator
 *
 */
public class Desk {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int n=6;
		//长度数组
		int[] l = {2,2,1,1,3,3};
		//权重数组
		int[] w = {4,3,5,5,2,1};
		//锯掉标记数组,0为保留,1为锯掉
		int[] b = {0,0,0,0,0,0};
		desk(l, w, b, l.length-1, curW);
		//desk1(l, w, b, 0, curW);
		System.out.println(minW);
		
		//System.out.println(isBlance(l, b));
	}
	//最小代价,初始化为所有代价和,此处省略
	static int minW = 100;
	//当前代价
	static int curW = 0;
	/**
	 * 从后往前递归,分两种情况,桌腿锯掉或是保留
	 * @param l 长度
	 * @param w 重量
	 * @param b 是否锯腿
	 * @param k 第k条腿
	 */
	public static void desk(int [] l, int [] w, int []b, int k, int curW) {
		int temp[] = new int[b.length];
		System.arraycopy(b, 0, temp, 0, b.length);
		//特别注意这个判断和下一个判断之间的顺序
		if(isBlance(l, temp)){//检测桌子是否平衡
			for(int i=0; i<l.length; i++){
				System.out.print(temp[i]);
			}
			System.out.println();
			if(minW>curW){//平衡,考虑其代价
				minW = curW;
			}
		}
		if(k<0)
			return;
		//不锯第k条
		desk(l, w, temp, k-1,curW);
		//锯掉第k条
		temp[k]=1;
		desk(l, w, temp, k-1 ,curW+w[k]);
	}
	/**
	 * 从前往后递归,分两种情况,桌腿锯掉或是保留
	 * @param l 长度
	 * @param w 重量
	 * @param b 是否锯腿
	 * @param k 第k条腿
	 */
	public static void desk1(int [] l, int [] w, int []b, int k, int curW) {
		int temp[] = new int[b.length];
		System.arraycopy(b, 0, temp, 0, b.length);
		//特别注意这个判断和下一个判断之间的顺序
		if(isBlance(l, temp)){//检测桌子是否平衡
			for(int i=0; i<l.length; i++){
				System.out.print(temp[i]);
			}
			System.out.println();
			if(minW>curW){//平衡,考虑其代价
				minW = curW;
			}
		}
		if(k>=l.length)
			return;
		//不锯第k条
		desk1(l, w, temp, k+1,curW);
		//锯掉第k条
		temp[k]=1;
		desk1(l, w, temp, k+1 ,curW+w[k]);
	}
	/**
	 * 使用动态规划求解
	 */
	/**
	 * @param l 桌腿长度数组
	 * @param b 是否锯掉数组,1锯掉
	 * @return 是否平衡
	 */	
	public static boolean isBlance(int [] l, int []b) {
		int max = 0;
		int len = 0;
		//找到数组中最大值max
		for(int i=0; i<l.length; i++){
			if(l[i]>max)
				max = l[i];
			if(b[i]==0)
				++len;
		}
		//将没锯的桌子以长度为key统计出现次数
		int count[] = new int[max+1];
		for(int i=0; i<l.length; i++){
			if(b[i]==0){
				count[l[i]]++;
			}
		}
		//找到长度最大桌腿,判断其次数是否大于一半
		for(int i=max; i>=0; i--){
			if(count[i]>0){
				if(count[i]>(len/2))
					return true;
				else
					break;
			}
		}
		return false;
	}
}

原文地址:https://www.cnblogs.com/yan456jie/p/5369371.html