最近一段时间都在被虐,是时候总结一下遇到的问题,准备新一轮被虐。
在这里总结一下与砝码有关的问题,砝码只是个代名词,算法可以运用到其他的场景下才是最重要的。
一、砝码表示范围的问题
所谓砝码的表示范围,即在一定范围的重量需要使用多少个砝码的问题。这类问题需要数学知识,在此向数学势力低头。
首先理解题意,一般问题会告诉我们砝码是否必须同边。(这里说到的被称物体都放在同一边)
如果必须同边,那么每个砝码的状态只有两种,要么放,要么不放。到这里,是不是觉得有点熟悉有陌生的感觉?如果把砝码看成电路的开关呢?想不到吧,这个问题纯粹是进制问题了。进制问题啊!!!为什么我对着电脑看来这么久都没想到
0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 1 | 1 | 1 | 1 | 1 | 1 |
如上图的7位二进制可以表示的数字范围是:0~127(27-1)。所以七个不同的砝码的可以表示的范围也就是[0,127]
如果不是必须同边,那么每个砝码有三种状态,与重物异侧,与重物同侧,不放。有上面可知,这也是个进制问题,只是严格意义上不能称之为三进制,因为这种进制比较特殊。如下图:
-1 | -1 | -1 | -1 |
0 | 0 | 0 | 0 |
1 | 1 | 1 | 1 |
因为砝码放在重物同侧相当于减法,所以4位该进制表示的范围是:-40~40。40是这么来的:(34-1)/2,这里需要除以一个二,因为这个表示法是以0对称的。
已知砝码个数,求表示范围:
核心代码:
int ans = (pow(3,n)-1)/2;
在这里建议手动乘方:
for(int i=1;i<=n;i++)
{r = 3*r;}
ans = (r-1)/2;
已至范围求砝码数: 核心代码:
int ans = log(2*n+1,3);
或:
int i = 1; int m = 1; int k = 3;
while(m<n){k = k*3;m = (k-1)/2;i++; } //i即为答案
二、已知砝码重量和个数,求砝码可以表示的重量。
这个问题还是逃不过动态规划了,也就是俗称dp数组,最重要是要找到递推公式。讲到递推公式,肯定离不开数学,所有再次向数学势力低头。
假设有n种砝码,每种有m1…mn,问可以称出的重量。在这里最重要是找到每个情况与前一种情况的关系。当砝码规格只有一种时,个数为m1个:f(1)=m1 。当砝码规格有两种,个数为m1 ,m2 ,f(2)=f(1)+x。关键在于如何确定x。
核心代码:
int n; //有n种砝码
int w[],m[],d[]; //w[]表示每种砝码的重量,m[]表示每种砝码的个数,d[]表示可以表示的重量,d[i]=1表示i可表示。
int sum; //记录所有砝码用完可表示的最大重量。
int fmaxsum; //用来记录每种情况可表示的最大重量。
d[0]=1; //注意要算上0.
for(int i=1;i<m[0];i++){
d[i*w[0]]=1; //把第一种砝码的所有情况进行标记。第一种情况需要单独列出是因为无法递推,例如数列中的a0。
}
fmaxsum = w[0]*m[0]; //记录当前可表示的最大值。
int i = 1; //由第二种情况开始递推。
int c; //c起试探作用。试探在未加第i+1种砝码时可能称到的情况。
int nw; //nw用来记录新的重量。
while (i < n)
{
for (j = 1; j <=m[i]; j++) //第i种砝码的个数最多为m[i]
{
for(c=0;c<=fmaxsum; c++) //c用来试探。
{
nw = c + j*w[i];
if (flag[c]==1&&flag[nw]==0) //只要在未加当前砝码时,可以表示出来,那新的重量即可表示
{
flag[nw] = 1;
}
}
}
fmaxsum = fmaxsum + m[i] * w[i]; //更新砝码的可称的最大重量
i++;
}
计算数量遍历一次数组d即可。
三、已知砝码重量和个数,算每种重量的砝码表示需要使用的最少砝码数。
同样时一个递推过程,如有砝码1,2,4,8各1个,则先把无需递推即:
d[1]=d[2]=d[4]=d[8]=1;
然后得到递推公式d[i]=d[i-w[j]]+1;在这里需要得到最少这种最佳情况。
核心代码:
int w[4]={1,2,4,8}; //注意w[]要按升序排列。
d[0]=0; //注意d[0]为0.
for(int i=1;i<=m;i++){
d[i]=d[i-w[0]]+1;
for(int j=1;j<4;j++){
d[i]=min(d[i-w[j]]+1,d[i]); //每种情况进行比较,得到最优。
}
}
谢谢大家,有遗漏的我会继续补充。我先去准备新一轮被虐啦!在这里再次向数学势力低头。