竞赛题算法优化

13 篇文章 0 订阅
用天平称重时,我们希望用尽可能少的砝码组合称出尽可能多的重量。
* 如果只有5个砝码,重量分别是 1,3,9,27,81。
* 则它们可以组合称出1到121之间任意整数重量(砝码允许放在左右两个盘中)
* 例如:
* 用户输入:
* 5
* 程序输出:
* 9-3-1
* 用户输入:
* 19
* 程序输出:
* 27-9+1
* 输入:
* 41
* 输出:
* 81-27-9-3-1

* </pre>

package com.ccl.algo;

/**
 * @author changlun.cheng
 * 
 *         <pre>
 * 用天平称重时,我们希望用尽可能少的砝码组合称出尽可能多的重量。
 * 如果只有5个砝码,重量分别是 1,3,9,27,81。
 * 则它们可以组合称出1到121之间任意整数重量(砝码允许放在左右两个盘中)
 * 例如:
 * 用户输入:
 * 5
 * 程序输出:
 * 9-3-1
 * 用户输入:
 * 19
 * 程序输出:
 * 27-9+1
 * 输入:
 * 41
 * 输出:
 * 81-27-9-3-1
 * </pre>
 */
public class Weight {

	/**
	 * 思路一:把1,3,9,27,81,-1,-3,-9,-27求全排列, 记下值在1-121之间的数并打印;<br/>
	 * 思路二:把1,3,9,27,81转为3进制数; <br/>
	 * 思路三:贪心算法;<br/>
	 * 
	 * 思路四: (1) 被称物质的质量计算的数学原理:设被称物质m放在天平左边,根据天平平衡原理,左边质量应等于天平右边质量。 <br/>
	 * (2) 问题关键在于算法中如何体现砝码放在天平左边
	 * ,右边或没有参加称量。这里可以用-1,1,0表示砝码放在天平左,右和没有参加称量,再没有其他数,所以称为三进制数,每个砝码都有这样的三种状态。<br/>
	 * (3)
	 * 被称物体质量计算:m=a*81+b*27+c*9+d*3+e。这里a,b,c,d,e分别表示81,27,9,3,1克的砝码是放在天平的左边,
	 * 右边或是没用<br/>
	 */

	public final int weight[] = new int[] { 1, 3, 9, 27, 81 };

	public java.util.List<Integer> list = new java.util.ArrayList<Integer>();

	public final int length = 5;

	/**
	 * 思路二
	 * 
	 * @param wei
	 */
	public void ternary(int wei) {

		int w = 81, i = 4;

		int warray[] = new int[] { 0, 0, 0, 0, 0 };

		/* 求wei对应的3进制数 */
		while (wei != 0) {

			if (w > wei) {
				w /= 3;
				i--;
			} else {

				wei -= w;
				warray[i]++;
			}

		}
		/**
		 * 修改,逢3向前进1,逢2原位改为-1并向前进1
		 */
		for (i = 0; i < 4; i++) {
			if (warray[i] == 3) {

				warray[i] = 0;
				warray[i + 1]++;
			} else if (warray[i] == 2) {
				warray[i] = -1;
				warray[i + 1]++;

			}
		}

		/**
		 * printf
		 */
		boolean flag = true;
		for (w = 81, i = 4; i >= 0; i--, w /= 3) {

			if (warray[i] > 0 && !flag)
				System.out.print("+");
			if (warray[i] != 0) {
				System.out.print("" + warray[i] * w);
				flag = false;
			}
		}
		System.out.println();

	}

	/**
	 * 求组合
	 * 
	 * @param array
	 */
	public void group(int[] array) {

		int length = array.length;

		int temp[] = new int[2 * length];

		int index = 0;
		for (int i = 0; i < length; i++) {
			temp[index++] = -array[i];
			temp[index++] = array[i];
		}
		index = 0;
		while (true) {

			index++;
			if (index == 2 * length)
				break;

			for (int i = 0; i < 2 * length; i++) {
				int sum = ran(array);
				if (sum >= 1 && sum <= 121) {
					list.add(sum);
				}
			}

		}

	}

	private int ran(int[] array) {

		int sum = 0;

		return sum;
	}

	public static void main(String[] args) throws Throwable {

		Weight w = new Weight();

		java.util.Scanner in = new java.util.Scanner(System.in);

		int wei = in.nextInt();

		w.nest(wei);

		w.ternary(wei);

		w.group(w.weight);
	}

	/**
	 * 思路四
	 * 
	 * @param wei
	 */
	private void nest(int wei) {

		int[] a, b, c, d, e;
		a = b = c = d = e = new int[] { -1, 0, 1 };/* 指向同一heap内存 */

		for (int ai : a) {
			for (int bi : b) {
				for (int ci : c) {
					for (int di : d) {
						for (int ei : e) {
							if (wei == ai * 81 + bi * 27 + ci * 9 + di * 3 + ei
									* 1)
								System.out.println(ai * 81 + "+" + bi * 27
										+ "+" + ci * 9 + "+" + di * 3 + "+"
										+ ei * 1);
							else
								continue;
						}
					}
				}
			}
		}

	}

}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值