zoukankan      html  css  js  c++  java
  • WUTOJ 1284: Gold Medal(Java)

    1284: Gold Medal

    题目

      有N个砝码,重量为:3i-1(1<=i<=N),有一块重量为 W 的金牌。现在将金牌放在天平的左边。你需要将砝码放在左边右边使得天平平衡,如果不能平衡输出"No way!",N个砝码不需要全部用完。更多内容点击标题。

    参考

    果7的博客

    分析

      说实话,我也没想到这种做法,看的参考博客才明白的。(感觉他有部分代码处理的不是很好,可能是语言不同的关系吧。)
      没见过这类题的话,说实话不容易一下子想到居然和进制居然有一点点关系。
      不得不说砝码的重量很灵性。我们可以尝试在这里入手。首先将金牌的重量 W 转成三进制的,由于长度较大所以直接用数组保存比较好(我用的byte[])。下面举个例子:
    输入:

    4 16
    

    输出:

    LEFT:3 9
    RIGHT:1 27
    
    

    步骤:

    通俗讲:
    将金牌分成9,6,1三部分(提醒:金牌是固定放在左边的。16的三进制为121),然后发现砝码中有1,
    于是就把1放在右边和左边的1平衡,然后继续,发现没有重量为6的砝码,但是你发现有重量为39的砝码,
    于是就把3放左边,9放在右边,这样就与左边的6平衡了。继续,左边还有9,可是你还剩一个砝码(27),
    根本不能平衡。于是你尝试将上一步中的9放在左边,此时左边有39和金牌的16一共是28,右边只有1,
    但是还剩一个砝码(27),放在右边刚刚好。
    
    代码流程:
    16转成三进制为:121  // 左边高位,右边低位0位是'1',所以3^0=1放在右边
    第1位是'2',权重是3^1=3,所以2*3=6,因为6不是3的幂,可是6=9-393都是3的幂,于是将3放
    在左边,然后将121变成2212位是'2',权重是3^2=9,所以2*9=18,因为18不是3的幂,可是18=27-9,279都是3的幂,于是
    将9放在左边,然后将221变成12214位是'1',权重是3^3=27,所以1*27=27,是3的幂,于是将27放在右边。
    

    代码

    /**
     * time 741ms
     * @author PengHao
     * @version A1.0
     * @date 2019-04-29 下午5:39:25
     * Environment:	Windows 10
     * IDE Version:	Eclipse 2019-3
     * JDK Version:	JDK1.8.0_112
     */
    
    import java.io.BufferedInputStream;
    import java.util.Scanner;
    
    public class Main {
    	/**
    	 * @Field <code>wTernary</code> W的三进制字节数组,下标从0开始
    	 */
    	private byte[] wTernary;
    	/**
    	 * @Field <code>leftArr</code> 左边的砝码情况
    	 */
    	private byte[] leftArr;
    	/**
    	 * @Field <code>rightArr</code> 右边的砝码情况
    	 */
    	private byte[] rightArr;
    	/**
    	 * @Field <code>tab</code> 3的n次幂(0<=n<=29),下标从0开始
    	 */
    	private long[] tab;
    	/**
    	 * @Field <code>ARR_LENGTH</code> 数组长度30
    	 */
    	private int ARR_LENGTH = 30;
    
    	public Main() {
    		Scanner sc = new Scanner(new BufferedInputStream(System.in));
    		initTab(); // 初始化
    		int N, W;
    		while (sc.hasNext()) {
    			N = sc.nextInt();
    			W = sc.nextInt();
    			wTernary = toTernary(W); // 转换成三进制
    			weighing(wTernary); // 称重
    			if (numOfWeights() <= N) {
    				output(); // 输出
    			} else {
    				System.out.println("No way!");
    			}
    			System.out.println(); // 每组数据末尾空一行
    		}
    		sc.close();
    	}
    
    	/**
    	 * Initialize <code>tab[]</code>
    	 * 
    	 * @see #tab
    	 */
    	private void initTab() {
    		tab = new long[ARR_LENGTH];
    		tab[0] = 1;
    		for (int i = 1; i < ARR_LENGTH; i++) {
    			tab[i] = tab[i - 1] * 3;
    		}
    	}
    
    	/**
    	 * Converts an integer to a ternary byte array
    	 * 
    	 * @param x 整数
    	 * @return x的三进制字节数组
    	 */
    	private byte[] toTernary(int x) {
    		byte[] y = new byte[ARR_LENGTH];
    		for (byte i = 0; i < ARR_LENGTH && x > 0; i++) {
    			y[i] = (byte) (x % 3);
    			x /= 3;
    		}
    		return y;
    	}
    
    	/**
    	 * @param x 需要称的重量
    	 * @see #leftArr
    	 * @see #rightArr
    	 */
    	private void weighing(byte[] x) {
    		leftArr = new byte[ARR_LENGTH]; // 保存左边砝码
    		rightArr = new byte[ARR_LENGTH]; // 保存右边砝码
    		for (int i = 0; i < ARR_LENGTH; i++) {
    			switch (x[i]) {
    			case 1:
    				rightArr[i] = 1; // 砝码3^i放到右边
    				break;
    			case 2:
    				leftArr[i] = 1; // 砝码3^i放到左边
    				x[i + 1]++; /// 要研究一下自增和赋值谁快
    				break;
    			case 3:
    				x[i + 1]++;
    				break;
    			default:
    			}
    		}
    	}
    
    	/**
    	 * @return 砝码个数
    	 */
    	private int numOfWeights() {
    		int num; // 砝码个数
    		for (num = ARR_LENGTH - 1; num >= 0; num--) {
    			if (0 != leftArr[num] || 0 != rightArr[num]) {
    				num++;
    				break;
    			}
    		}
    		return num;
    	}
    
    	/**
    	 * Output
    	 */
    	private void output() {
    		outputArr("LEFT:", leftArr);
    		outputArr("RIGHT:", rightArr);
    	}
    
    	/**
    	 * @param LR  左右?
    	 * @param arr 需要输出的砝码
    	 */
    	private void outputArr(String LR, byte[] arr) {
    		boolean first = true; // 是不是第一个砝码
    		System.out.print(LR);
    		for (int i = 0; i < ARR_LENGTH; i++) {
    			if (1 == arr[i]) {
    				if (first) {
    					first = false;
    				} else {
    					System.out.print(" "); // 不是这一边的第一个砝码,要输出空格
    				}
    				System.out.print(tab[i]); // 输出砝码重量
    			}
    		}
    		System.out.println();
    	}
    
    	public static void main(String[] args) {
    		new Main();
    	}
    }
    

    写在最后:

    1. 如需转载,请于首页至少注明链接形式的wowpH的博客这几个字;
    2. 代码原创,如需公开引用,不能删除首行注释(作者,版本号,时间等信息)。
    3. 如果有疑问欢迎评论留言,尽量解答。

  • 相关阅读:
    redis实现高并发下的抢购/秒杀功能
    redis分布式锁的实现(setNx命令和Lua脚本)
    【JAVA代码审计】——1、Spring框架知识篇
    使用edjpgcom工具制作一句话图片木马
    史上最强内网渗透知识点总结
    2018年云上挖矿分析报告
    Solidity 安全:已知攻击方法和常见防御模式综合列表
    【PHP渗透技巧拓展】————3、LFI、RFI、PHP封装协议安全问题学习
    【PHP渗透技巧拓展】————2、利用 Gopher 协议拓展攻击面
    【RPO技巧拓展】————5、RPO攻击初探
  • 原文地址:https://www.cnblogs.com/wowpH/p/11060804.html
Copyright © 2011-2022 走看看