你有一架天平。现在你要设计一套砝码,使得利用这些砝码可以称出任意 小于等于 NN 的正整数重量。
那么这套砝码最少需要包含多少个砝码?
注意砝码可以放在天平两边。
输入包含一个正整数 N N N。
输出一个整数代表答案。
7
3
3 个砝码重量是 1、4、6,可以称出 1 至 7的所有重量。
1 = 1;
2 = 6 − 4(天平一边放 66,另一边放 44);
3 = 4 − 1;
4 = 4;
5 = 6 − 1;
6 = 6;
7 = 1 + 6;
少于 3 个砝码不可能称出 1 至 7 的所有重量。
对于所有评测用例, 1 ≤ N ≤ 1000000000 1 ≤ N ≤ 1000000000 1≤N≤1000000000。
最大运行时间:1s
最大运行内存: 512M
这道题,如果固定一下,使得砝码只能在一边进行称重的话,那么题目会简单很多,大家一定可以很快的想到对于一个砝码,我们只有选和不选(1和0)两个状态,那么我们想要表示1-N中所有的重量的话,可以最少选择 [ l o g 2 ( N + 1 ) ] [log_2(N+1)] [log2(N+1)]个砝码就可以表示1-N中所有的重量了。
其实这个使用的是二进制的知识,比如说我们手上有1、2、4这三个砝码,那么我们就可以表示000、001、010、011、100、101、110、111这八种重量,其中000在这道题目中可以不计入重量,那么也就是可以表示1-7这七种重量,这个应该还是比较容易想到的
为什么是(N+1)为底?我们可以特殊化N=8时,那就需要4位来表示
但是很可惜,这道题多了一种状态,就是砝码是可以放在另一边来称重的,那么使用二进制就是无解了。。。。
于是!!!我们引入了三进制!!!
我们这道题对于每个砝码其实有三个状态,也就是放到天平左侧,不放,放到天平右侧,这恰好可以对应三进制的三种状态:1,0,-1,因此三进制更符合于这道题的求解方案
其实大家听到三进制,第一反应都是用0,1,2三个数来表示数的进制方法,但是其实我们这道题目中使用的三进制是对称三进制(也称平衡三进制1),
首先我们需要知道,平衡三进制是由
1
,0
,-1
构成的,它的基数也是3
(因为可能由三种值),由于-1
写成数字不太方便,这里的-1
我们都用Z
来代替我们先看看几种平衡三进制的表示:
平衡三进制 十进制 Z -1 0 0 1 1 ZZ -4 Z0 -3 Z1 -2 1Z 2 10 3 11 4 然后我们发现,平衡三进制是可以不重复地完整地表达 [ − 3 n − 1 2 , 3 n − 1 2 ] ( n ∈ Z ) [-\frac{3^n-1}{2},\frac{3^n-1}{2}](n\in Z) [−23n−1,23n−1](n∈Z)中的每一个数的。
所以,根据上面的思路,我们想要求出 1 − N 1-N 1−N中的每一种重量,只需要求解出 3 n − 1 2 ≥ N \frac{3^n-1}{2}\geq N 23n−1≥N,然后取 n n n的最小值即可。
我们解出来 n ≥ l o g 3 ( 2 N + 1 ) n\geq log_3(2N+1) n≥log3(2N+1)
这就是我们的最终结果了
而我们也可以很容易地得出,我们所需要的砝码的重量⚓️分别为 1 、 3 、 9 ⋯ 3 n − 1 1、3、9\cdots3^{n-1} 1、3、9⋯3n−1
当然这上面只是数学的推导,我们写代码只需要枚举出这个 n n n的值就可以了
package com.lanqiao;
import java.util.Scanner;
/**
* @author 王宇哲
* @date 2022/4/2 15:14
*/
public class 最少砝码 {
/**
* 需要能称出1-N中所有的重量
*/
static int N;
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
N = scanner.nextInt();
int n = 0;
// 存储3^n的值,初始为3^0=1
// 记得开long,否则会爆掉
long num = 1;
//通过枚举推到出一个n使得3^n>=2*N+1
while (num < 2L * N + 1) {
//找后面一个n
n++;
//得出3^n的值
num *= 3;
}
System.out.println(n);
}
}
平衡三进制,也称为对称三进制,是一种以3为基数,以-1,0,1为基本数码的三进制计数体系。俄罗斯科技人员曾经将其应用到计算机系统,也被应用于光子计算机相关研究中。 ↩︎