• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号
您的位置:首页 > 程序设计 >编程问答 > 算法问题:把一个数分成m个数,有且仅有一个最大数

算法问题:把一个数分成m个数,有且仅有一个最大数

作者:佚名 字体:[增加 减小] 来源:互联网 时间:2017-06-07

佚名通过本文主要向大家介绍了二叉树结点个数算法,贪心算法删数问题,函数零点个数问题,零点个数问题,复合函数零点个数问题等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com
问题:算法问题:把一个数分成m个数,有且仅有一个最大数
描述:

今天写一个游戏的时候遇到了这么一个算法问题,因为觉得自己写的算法不是很好,又想不出其他解法,想来求助一下。

下面详细描述一下题目:

有一个整数n,分成m个整数(m个整数之和等于n),m个整数中有且仅有一个最大数且都不为0。返回一个组合即可,但是该组合应该是所有组合里随机的一个。
eg:

n=4,m=2, 分解后整数为 3,1
n=9,m=2, 分解后整数为 8,1或7,2或6,3或5,4

下面是我的代码(js):

function ran(nNum,mNum) {
    var m = nNum - mNum + 1;
    var n = nNum%mNum == 0?nNum/mNum+1:Math.ceil(nNum/mNum);
    var bestNum = Math.floor(Math.random()*(m-n)+n);
    var currentNum = 0;
    var arrList = [];
    arrList.push(bestNum);
    currentNum+=bestNum;
    for(var i=1;i<mNum;i++) {
        if(i == mNum-1) {
            var rad = nNum - currentNum;
            if(rad == bestNum) {
            } else {
                arrList.push(rad);
            }
        } else {
            var min = (nNum - currentNum) - (mNum-1-i)*(bestNum-1);
            if(min<0) {
                min = 1;
            }
            var max = bestNum-1;
            if(nNum - currentNum - (mNum-1-i) < bestNum) {
                max = nNum - currentNum - (mNum-1-i);
            }
            var rad = Math.round(Math.random()*(max-min))+min;
            currentNum += rad;
            if(currentNum>nNum) {
                currentNum -= rad;
                i--;
                continue;
            } else {
                arrList.push(rad);
            }
        }
    }
    console.log(arrList);
}

个人算法能力薄弱,见谅


解决方案1:

先将n-1分隔成m个随机数,然后取其中最大值进行+1

解决方案2:

function ran(nNum, mNum) {
  var n = nNum - mNum;
  var maxNum = 1;
  var maxNumIndex = 0;
  var numArray = [];
  if (n > 0) {
    for (var i = 0; i < mNum - 1; i++) {
      numArray.push(getNum(i) + 1);
    }
    if (n === maxNum) numArray[maxNumIndex]--;
    numArray.push(n + 1);
    console.log(numArray);
  } else {
    console.log("unsolvable");
  }

  function getNum(i) {
    var m = Math.ceil(Math.random() * n);
    if (m === maxNum) {
      m = getNum(i);
    } else {
      n -= m;
      if (m > maxNum) {
        maxNum = m;
        maxNumIndex = i;
      }
    }
    return m;
  }
}

解决方案3:

最大数max = n - m + 1,剩下的都为1,这样分可以吗?

function foo(n, m) { // 名字就不起了,就叫这个吧
    var average = Math.floor(n / m); // average >= 1
    var max = 0;
    var left = n;
    var arr = [];
    for (var i = 0; i < m; i++) {
        // 这里是关键,每次随机得到一个大于0的值,但必须确保余下的数足够剩下的元素分配
        // 一开始我使用的是 Math.random() * (left - (m - i - 1)),但是效果不好
        // 会导致随机性很差,大数都集中在前面的元素中,而后面的元素往往都是1
        // 这是由于最初的算法在开始时的随机空间很大,所以也容易得到较大的数的原因,而越到后面,剩下的可分配的值越小
        // 后来我改进了算法,加了一个average,用来平均每次的随机空间,测试下来效果挺不错
        arr[i] = i == m - 1 ? left
            : Math.floor(Math.random() * (left - (m - i - 1) * average)) + 1;
        left -= arr[i];
        if (arr[i] > arr[max]) {
            max = i;
        } else if (arr[i] == arr[max] && arr[i] >= average) { // 这里用来修正最大值,确保最大值的元素只有一个
            arr[i]--;
            arr[max]++;
        }
    }
    console.log(arr);
    return arr;
}

测试代码:

foo(4, 2);
foo(4, 2);
foo(4, 2);
foo(8, 3);
foo(8, 3);
foo(8, 3);
foo(8, 3);
foo(20, 7);
foo(20, 7);
foo(20, 7);
foo(20, 7);
foo(20, 7);
foo(20, 7);
foo(20, 7);

下面是某一次测试的结果:

[3, 1]
[1, 3]
[1, 3]
[4, 2, 2]
[3, 1, 4]
[4, 2, 2]
[4, 2, 2]
[1, 2, 4, 2, 6, 1, 4]
[3, 6, 1, 4, 2, 1, 3]
[1, 1, 6, 5, 1, 2, 4]
[3, 4, 5, 1, 2, 3, 2]
[2, 8, 1, 3, 2, 2, 2]
[4, 1, 7, 1, 2, 2, 3]
[3, 1, 2, 4, 5, 2, 3]

解决方案4:

大概有个思路:
生成一组m个随机数,并只有一个最大数
取得这组数的和sum,然后n/sum得到比例s
再把这组数都乘以s并取整

问题在取整后总和可能会小于n,或者是最大值和次大值差值很小时取整后可能会相等
对这两个情况特殊处理一下就可以了

因为生成随机数时不用考虑n,在生成完成后再用比例去缩放数值,所以随机性应该还可以
代码晚点看情况补上

解决方案5:

https://jsfiddle.net/hsfzxjy/aevc56ts/2/

function random (min, max) {
    if (min >= max) return max;
    return Math.floor(Math.random() * (max - min + 1)) + min;
}

function split (n, m, result) {
    if (m === 1) {
      result.push(n);
    return;
  }
  
  let num = random(1, n - m + 1);
  result.push(num);
  split(n - num, m - 1, result);
}

function ran (n, m) {
    let result = [];
  split(n, m, result);
  result.sort((a, b) => (b - a));
  if (result[0] === result[1]) {
      result[0] ++;
    result[1] --;
  }
  return result;
}

其实并不是真正的随机,每种情况概率并不相等

---Update---

另一种实现,相对均匀: https://jsfiddle.net/hsfzxjy/f5r50zr4/4/

function random (min, max) {
  // 从闭区间[min, max]随机取整数
  if (min >= max) return max;
  return Math.floor(Math.random() * (max - min + 1)) + min;
}

function selectANumber (arr) {
  // 从数组 arr 中随机选一个数,删除并返回
  let index = random(0, arr.length -1);
  return arr.splice(index, 1)[0];
}

function ran (n, m) {
  // 核心思想:从1~n-1中随机取出m-1个数来
  let indices = [], selected = [0, n];
  let i;
  
  for (i = 1; i < n; ++i) indices.push(i); // 初始化为 0~n-1
  
  for (i = 1; i < m; ++i) selected.push(selectANumber(indices));
  
  selected.sort((a, b) => (a - b));
  
  let result = [];
  
  // 构造答案
  for (i = 1; i < selected.length; ++i) 
    result.push(selected[i] - selected[i - 1]);
    
  result.sort((a, b) => (b - a));
  
  // 调整最大数
  if (result[0] === result[1]) {
    result[0] ++;
    result[1] --;
  }
  
  return result;
}

基本思路:将 n 分成 m 份,等价于 将 n 个球排成一排,在空隙中插入 m-1 个隔板


分享到:QQ空间新浪微博腾讯微博微信百度贴吧QQ好友复制网址打印

您可能想查找下面的文章:

  • 算法问题:把一个数分成m个数,有且仅有一个最大数

相关文章

  • 2017-06-07 有c语言的基础学习java容易上手吗?
  • 2017-06-07 pythonrequestspost大文件和获取进度条
  • 2017-06-07 (python)我写的Xpath为什么爬取不到内容
  • 2017-06-07 (python)pip安装flower模块的问题
  • 2017-06-07 如果栈的数目多于2个,如何实现共享空间
  • 2017-06-07 C#操作CookiesSparkDistinct操作的DAG问题
  • 2017-06-07 在OSCGit中部署django演示项目
  • 2017-06-07 (VFP)如何将网页上的数据,读出来?
  • 2017-06-07 mongoDB等非关系型数据库和mysql等关系型数据库的应用场景有何异同?
  • 2017-06-07 按劳分配按写分配和不按写分配的访存次数差别

文章分类

  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号

最近更新的内容

    • 七牛上的文件外链怎么加成https的?
    • 文本单趟匹配问题
    • 七牛在开发html5应用时,上传数据能否做到直接上传到七牛服务器?
    • 求JavaSocket大神点拨一个JavaSocket的连接故障如何排解?
    • (golang)new方法和声明一个类型有什么区别
    • 如何使用memcached缓存django中的template和model?
    • 编写一个JAVA程序,解决该问题。
    • Discuz31使用七牛远程附件后论坛上传图片或附件均不是远程地址
    • IndexError:listindexoutofrange
    • 七牛私有云下载要验证,那直接audio里面播放链接呢

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有