求一算法,一个自然数M,怎样分成N份,每份是10的倍数。

    function randomSplit(m,n,minv,maxv){
        var res=[];
        while(n>0){
            l = Math.max(minv,m-(n-1)*maxv);
            r = Math.min(maxv,m-(n-1)*minv);
            num = Math.floor(Math.random() * (l - r)/10)*10 + r;
            n -= 1;
            m -= num;
            res.push(num);
        }
        return res;
    }    

我组装了一个,有时候不准确,有时候准。有误差的时候多。

3000 3 1200 1800
[1000, 1050, 960] "=" 3010
这个就误差了10.

3000 3 1200 1800  
[660, 1150, 1190] "=" 3000

这个就正好3000.

minv,我取了。 M的40%
maxv,我取了, M的60%

minv是,每份最小值,
maxv是,每份最大值。

有大神吗?帮我看看吧,实在搞不定了。

阅读 2.1k
2 个回答

M存在范围

minv*n <= M <= maxv*n

如 3000 3 1200 1800 错误入参
M至少得3600,3000不符合范围要求,自相矛盾,入参错误又未进行参数检测,异常再正常不过。

function randomSplit(m, n, minv, maxv) {
 if (m < minv * n || m > maxv * n) {
     console.log("参数 不合法")
 return
 }

 var res = [];
 while (n > 0) {
    l = Math.max(minv, m - (n - 1) * maxv);
    r = Math.min(maxv, m - (n - 1) * minv);
    num = Math.floor(Math.random() * (l - r) / 10) * 10 + r;
    n -= 1;
    m -= num;
    res.push(num);
 }
 console.log(res)
 return res;
}
// 测试
randomSplit(4000,3,1200,1800)

你的问题有误啊,我觉得正确的描述是:

M∈N(这里的N表示自然数集合)
M=∑Vi
Vi%10=0
i∈1,2,3,...,n
minV≤Vi
maxV≥Vi

由此,你其实有一些内生的判断条件是

maxV*N>=M>=minV*N
M%10=0

否则肯定没法求解,这也是你第一个题M=3000,n=3,minV=1200,maxV=1800不能求解的原因。
此外这里没有限定是否允许Vi相等,所以如果仅仅是求取一个可能解,就不需要用到随机数,而是去凑一个最方便的可能解效率高一些。而单纯的取随机数可能置前面的数已经取好了,但后面的数则可能不可能满足条件。
所以完整的代码可以为:

function randSplit(m,n,minv,maxv){
  var rt=[];
  if( (m<0) || (m%10)!=0 || 
      (n<0) || (n%1)!=0  ||
      (minv<0) || (m<minv*n)||
      (maxv<0) || (maxv<minv) || (m>maxv*n) ){ // 可以分开直接给出那个参数不合法
        console.log("有参数不合法");
        return rt;
      }
   while (n > 0) {
     tL = Math.max( minv, m - (n-1)*maxv);
     tH = Math.min( maxv, m - (n-1)*minv);
     tmpN = Math.floor( Math.random()*( tH - tL )/10)*10 + tL ;
     rt.push(tmpN);
   }
   rt.sort(function(a, b){   return (a - b);});
   return rt;
}
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题