求一个随机算法

zilaishuichina 2015-10-22 06:16:56
已知一组不重复的数字,如
Array:3,6,9,2
数量有n个,n不固定

每一个数字对应一个权重值,如
Weight:30,50,40,100
和Array一一对应

现在希望按照权重随机m(m<=n)个不重复的Array中的数字出来,顺序不论,当每随机出一个数字之后,该数字对应的权重不纳入以后每一次的权重总和。

比如:
第一次的权重总和是220,对220做随机,得到一个随机数90,对应的是9,
从Array中剔除9,从Weight中剔除9对应的权重40
第二次的权重总和是220 - 9对应的权重40 = 180, 对180做随机,依次类推。

求一个简便的算法。

ps:按照权重随机一个出来是比较方便的
但是因为每次随一个出来之后,计算下一个之前,需要从Array中剔除已经被选中的数字,重新生成一个Array,并重新计算权重总和,重新计算一个随机数应该对应新Array数组的哪个元素,比较麻烦,所以想看有没有更简便的,比如能一次性把m个都确定下来的方法。


...全文
190 5 打赏 收藏 转发到动态 举报
写回复
用AI写文章
5 条回复
切换为时间正序
请发表友善的回复…
发表回复
zilaishuichina 2015-10-24
  • 打赏
  • 举报
回复
引用 3 楼 zhao4zhong1 的回复:
随机必然有重复,所谓“不重复的随机”实际上是洗牌。洗牌算法参考下面:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int d[6];
int i,n,a,b,t;
int c,j;
void main() {
    srand(time(NULL));
    printf("shuffle 0..n-1 demo\n");
    for (n=1;n<=5;n++) {/* 测试1~5个元素 */
        printf("_____n=%d_____\n",n);
        j=1;
        for (c=1;c<=n;c++) j=j*c;/* j为n! */
        j*=n*2;
        for (c=1;c<=j;c++) {/* 测试n*2*n!次 */
            for (i=0;i<n;i++) d[i]=i;/* 填写0~n-1 */
            for (i=n;i>0;i--) {/* 打乱0~n-1 */
                a=i-1;b=rand()%i;
                if (a!=b) {t=d[a];d[a]=d[b];d[b]=t;}
            }
            printf("%04d:",c);
            for (i=0;i<n;i++) printf("%d",d[i]);
            printf("\n");
        }
    }
    printf("shuffle 1..n demo\n");
    for (n=1;n<=5;n++) {/* 测试1~5个元素 */
        printf("_____n=%d_____\n",n);
        j=1;
        for (c=1;c<=n;c++) j=j*c;/* j为n! */
        j*=n*2;
        for (c=1;c<=j;c++) {/* 测试n*2*n!次 */
            for (i=1;i<=n;i++) d[i]=i;/* 填写1~n */
            for (i=n;i>1;i--) {/* 打乱1~n */
                a=i;b=rand()%i+1;
                if (a!=b) {t=d[a];d[a]=d[b];d[b]=t;}
            }
            printf("%04d:",c);
            for (i=1;i<=n;i++) printf("%d",d[i]);
            printf("\n");
        }
    }
}
通常意义上的洗牌是均等概率的 对于带权重的洗牌,其实是需要按权重比生成一个新数组, 比如 Array:3,6,9,2 Weight:30,50,40,100 我需要生成一个长220(权重总和)的数组,包含30个3,50个6,40个9,100个2 然后洗牌, 然后从前往后取m个不重复的 所以当权重总和比较大的时候,这个洗牌的效率还是比较低的,尤其是当这个洗牌逻辑需要频繁调用的时候
赵4老师 2015-10-23
  • 打赏
  • 举报
回复
随机必然有重复,所谓“不重复的随机”实际上是洗牌。洗牌算法参考下面:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int d[6];
int i,n,a,b,t;
int c,j;
void main() {
    srand(time(NULL));
    printf("shuffle 0..n-1 demo\n");
    for (n=1;n<=5;n++) {/* 测试1~5个元素 */
        printf("_____n=%d_____\n",n);
        j=1;
        for (c=1;c<=n;c++) j=j*c;/* j为n! */
        j*=n*2;
        for (c=1;c<=j;c++) {/* 测试n*2*n!次 */
            for (i=0;i<n;i++) d[i]=i;/* 填写0~n-1 */
            for (i=n;i>0;i--) {/* 打乱0~n-1 */
                a=i-1;b=rand()%i;
                if (a!=b) {t=d[a];d[a]=d[b];d[b]=t;}
            }
            printf("%04d:",c);
            for (i=0;i<n;i++) printf("%d",d[i]);
            printf("\n");
        }
    }
    printf("shuffle 1..n demo\n");
    for (n=1;n<=5;n++) {/* 测试1~5个元素 */
        printf("_____n=%d_____\n",n);
        j=1;
        for (c=1;c<=n;c++) j=j*c;/* j为n! */
        j*=n*2;
        for (c=1;c<=j;c++) {/* 测试n*2*n!次 */
            for (i=1;i<=n;i++) d[i]=i;/* 填写1~n */
            for (i=n;i>1;i--) {/* 打乱1~n */
                a=i;b=rand()%i+1;
                if (a!=b) {t=d[a];d[a]=d[b];d[b]=t;}
            }
            printf("%04d:",c);
            for (i=1;i<=n;i++) printf("%d",d[i]);
            printf("\n");
        }
    }
}
zilaishuichina 2015-10-22
  • 打赏
  • 举报
回复
引用 1 楼 JiangWenjie2014 的回复:
0)初始化:数组[3,6,9,2],权重[30,50,40,100] 1)第一次选取,此时权重和是220,得到随机数90。对应数字9,权重40,把9跟数组中最后一个元素置换,权重数组也是如此置换。数组[3,6,2,9],权重[30,50,100,40] 2)第二次选取,此时权重和是180,得到随机数20。对应数字3,权重30,把3跟数组中倒数第二个元素置换,权重数组也是如此置换。数组[2,6,3,9],权重[100,50,30,40] 依次类推,最终随机得到的结果:第一个被选中的数在末尾,第二个被选中的数在倒数第二,第N个被选中的数在倒数第N的位置上。这样得到的还是随机的吗?
交换会涉及到每个元素的权重的重新计算,这个是需要遍历的 数组[3,6,9,2],权重[30,50,40,100] 实际上是 权重[0-29, 30-79, 80-119, 120-219] 举个例子 , 如果出现3 和 2的交换 则变成 数组[2,6,9,3],权重[100,50,40,30] 实际上 每个元素的权重均需要重新计算[0-99, 100-149, 150-189, 190-219]
JiangWenjie2014 2015-10-22
  • 打赏
  • 举报
回复
0)初始化:数组[3,6,9,2],权重[30,50,40,100] 1)第一次选取,此时权重和是220,得到随机数90。对应数字9,权重40,把9跟数组中最后一个元素置换,权重数组也是如此置换。数组[3,6,2,9],权重[30,50,100,40] 2)第二次选取,此时权重和是180,得到随机数20。对应数字3,权重30,把3跟数组中倒数第二个元素置换,权重数组也是如此置换。数组[2,6,3,9],权重[100,50,30,40] 依次类推,最终随机得到的结果:第一个被选中的数在末尾,第二个被选中的数在倒数第二,第N个被选中的数在倒数第N的位置上。这样得到的还是随机的吗?

64,691

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧