挑战你的智商。看似简单却考验功力的题 生成n个随机数 要求其和等于m
比如生成27 个随机数 27个随机数的和等于301 --------------------编程问答-------------------- 可以负数吗?可以的话,只要第27个数是301去减前26个数的和就可以了 --------------------编程问答-------------------- 确实考验功力楼主自己动手吧
--------------------编程问答--------------------
可以为0 但不能为负数 --------------------编程问答-------------------- 还是风的那个方法。 先取第一个随机数你n1 = R(0~301); 然后取 n2 = R(0~(301-n1)) .....最后来个乱序。 --------------------编程问答--------------------
如果我希望数值在平均值周围震荡呢? --------------------编程问答-------------------- 能重复不?能重复几次?
--------------------编程问答--------------------
可以重复 不能重复太多次 --------------------编程问答--------------------
重复26个1,然后301-26=275
然后乱序
算法完成
--------------------编程问答-------------------- 典型的排列组合问题,每个位置可能的数是0~9,从第一个位置开始,一次给一个随机数,每分配一个随机数,全局计算剩余数,如第一次分配了5,那么剩余数是301-5=296,第二次分配了9,剩余数就是296-9=287,当剩余数小于9时,后面位置分配的数则是0~剩余数。最后一个位置直接给剩余数即可,至此算法完成。 --------------------编程问答-------------------- 取到 301 的 27个数的平均值 为 11.148148148148148148148148148148。
然后 对其 进行 13 1 13 这样的 对称 计算 可以是 27个 无重复的 数,最后的合数可以是 301
所以在 在随机的时候 只要 随机 13 次 就够了, 而不是 26 次随机 --------------------编程问答--------------------
int w = 301;
Random random = new Random();
for (int r = 0; r < 27; r++)
{
int x = random.Next(w / (27 - r));
w -= x;
Console.WriteLine(x);
}
输出:
0
6
6
10
8
1
2
4
3
9
3
5
6
2
17
4
7
9
3
7
19
4
3
17
0
46
13 --------------------编程问答-------------------- 错了,无视。
--------------------编程问答-------------------- 错了,无视之。
不过只要处理一下最后以为就可以变正确了。
--------------------编程问答-------------------- 目测随机了26次,最后一次不是随机吧
int w = 301;
Random random = new Random();
for (int r = 0; r < 27; r++)
{
int w2 = 0;
if (r != 26)
w2 = w / (27 - r);
else
w2 = w;
int x = random.Next(w2);
w -= x;
Console.WriteLine(x);
}
--------------------编程问答--------------------
恩,最后一次不随机就正确了。第一次贴错了,急于更正,结果还是贴错了。
--------------------编程问答-------------------- 13 楼基本方向是对的 结果是错的 加几个参数 限制一下就可以了 --------------------编程问答-------------------- 感觉可以简化成两个数相加 --------------------编程问答--------------------
暂时将震荡值设置为平均值的一半
--------------------编程问答-------------------- 结果:10 13 14 5 11 9 11 12 9 10 16 9 13 10 11 3 8 15 11 8 16 15 13 10 12 13 14 --------------------编程问答-------------------- 插板法 --------------------编程问答--------------------
static int[] GetRandomNumbers(int count, int total)
{
//平均值
int avg = total / count;
//设震荡区间为平均值的一半
int range = avg / 2;
int[] arr = new int[count];
Random ran = new Random();
//将数组元素先设成平均值
for (int i = 0; i < arr.Length; ++i)
{
arr[i] = avg;
}
//随机获取2个数组元素,一个加上震荡值,一个减去震荡值
for (int i = 0; i < arr.Length; ++i)
{
int index = ran.Next(arr.Length);
if (i != index)
{
int add = ran.Next(range) + 1;
//不能减成负的
if (arr[index] - add >= 0)
{
arr[i] += add;
arr[index] -= add;
}
}
}
//修正数组元素,因为平均值很可能不是由整除得到的。
int last = total - avg * count;
for (int i = 0; i < last; ++i)
{
int index = ran.Next(arr.Length);
arr[index] += 1;
}
return arr;
}
--------------------编程问答-------------------- 按13楼的思路改了一下 --------------------编程问答-------------------- 尼玛 这10来行 代码 花了哥半天时间 好久不写程序 手生了 --------------------编程问答-------------------- 不写代码,只说思路
int m = 301;//总数
int n = 27;//个数
Random random = new Random();
int x = 0;
// int sum = 0; //用来验证和是否正确。
int[] arr = new int[n]; //用来保存结果
for (int i = 0; i < n; i++)
{
if (i!=n-1)
{
int avg = m /(n-i);//动态平均值 ,为余下的总数/余下组数
x = random.Next(avg * 2); //生成随机数 震荡范围为 0 ~ 平均值*2
m -= x; //总数中减去已生成数
}
else
{
x= m;
}
// sum += x;
arr[i] = x;
}
假设一根线段,总长N米,平均分成m段,这样有首位m+1个点
然后随机把点左/右移动即可,最后计算两点间隔
因为总长已经固定,无论你怎么移动点,结果都是一样
如果你说要平均,我们只需设置一个合理的移动阀值,让他不至于偏离这个平均线段太远就ok --------------------编程问答--------------------
说的不错 --------------------编程问答-------------------- 21楼太牛了
21楼不就是我自己吗
我都有点佩服自己了
我觉得这个问题可以作为招聘的笔试题了 有木有啊有木有 --------------------编程问答-------------------- 还有另外一个思路,把点看成糖葫芦
每个糖葫芦之间用不同系数的弹簧连着,直接拉动弹簧,他会根据系数自然伸展,不同弹簧系数不同,自然最后各段长度不同
如果要平均,还是一样选定合适的阀值,尽量分配系数差别不大的弹簧,就ok了 --------------------编程问答-------------------- 看来还真是值得思考的问题 --------------------编程问答-------------------- 楼上好思路,可以选取26个(1到300)
不重复的随机数,然后相邻的随机数相减,第一个数减0,最后一个被301减 --------------------编程问答-------------------- 你这叫重复么。。。你这简直就是单数字,,还叫随即啊。。。 --------------------编程问答--------------------
int Sum = 301;--------------------编程问答-------------------- 感觉题目有点怪 都被坑了 估计 301 那不是个单数吗 除什么都不可能整除 怎么能用除法呢 上面的大神 --------------------编程问答-------------------- 其实我觉得最简单的办法是这样 随便算 前26个可以都可以定义到一个范围里 301/27的平均值里 当前26个相加后结果 用301减去 就是第27个数
int Count = 27;
int[] ary = new int[Count];
for (int i = 0; i < Count; i++)
ary[i] = Sum / Count;
Random r = new Random();
for (int i = 0; i < Sum % Count; i++)
ary[r.Next(Count)]++;
for (int i = 0; i < 800; i++)
{
int a = r.Next(Count);
int b = r.Next(Count);
if (a != b && ary[a] > 0 && ary[b] > 0)
{
ary[a]--;
ary[b]++;
}
}
ary.ToList().ForEach(t => Console.Write(t + " "));
Console.ReadLine();
答案其实301都是固定的 应该这样利用 --------------------编程问答-------------------- 使用迭代法,逐个生成n个随机数,并逐个累加,
如果小于m,继续迭代
如果大于m,重新开始迭代
如果等于m,输出随机数列表 --------------------编程问答-------------------- 好问题呀 --------------------编程问答-------------------- 先生成一个0~301的随机数a,在生成一个0~(301-a)的随机数b,再生成0~(301-a-b)的随机数c。
循环,执行;不够的补0。 --------------------编程问答-------------------- 两个条件:27个数 & 和等于301 --------------------编程问答--------------------
这个思路也不错 路上我也想到了
生成 0~301 之间的 26个 随机数 从小到大排列一下 后面的值减去前面的值 就行了
--------------------编程问答-------------------- 太easy了,把301个1随机加进27个起始值为0的数组里就行了。
using System;
namespace RandomGenerator
{
class Program
{
const int SUM = 301;
const int SIZE = 27;
static void Main(string[] args)
{
int[] numberArray = new int[SIZE];
Array.Clear(numberArray, 0, numberArray.Length);
int seed = (int)DateTime.Now.Ticks;
Random random = new Random(seed);
for (int i = 0; i < SUM; i++)
{
int index = random.Next(0, SIZE);
numberArray[index]++;
}
int total = 0;
for (int i = 0; i < SIZE; i++)
{
total += numberArray[i];
Console.Write("{0} ", numberArray[i]);
}
Console.WriteLine();
Console.WriteLine("Total: {0}", total);
}
}
}
--------------------编程问答-------------------- 下面这个改进的算法,利用平均值原理,可以减少循环圈。这样的话,即使总合和数组很大,也能很快算出来。
using System;
namespace RandomGenerator
{
class Program
{
const int SUM = 300001;
const int SIZE = 270;
static void Main(string[] args)
{
int[] numberArray = new int[SIZE];
Array.Clear(numberArray, 0, numberArray.Length);
int seed = (int)DateTime.Now.Ticks;
Random random = new Random(seed);
int remainder = SUM;
int iter = 0;
while (remainder > 0)
{
int average = remainder / SIZE;
if (average == 0)
{
average = 1;
}
int index = random.Next(0, SIZE);
numberArray[index] += average;
remainder -= average;
//Console.WriteLine("remainder: {0}, average: {1}", remainder, average);
iter++;
}
Console.WriteLine("Loop size: {0}", iter);
int total = 0;
for (int i = 0; i < SIZE; i++)
{
total += numberArray[i];
Console.Write("{0} ", numberArray[i]);
}
Console.WriteLine("Total: {0}", total);
}
}
}
--------------------编程问答-------------------- 生成26个0-301的随机数,再把0和301加进去形成一个28个数的数组,排序后输出每两个数的差值即可。 --------------------编程问答--------------------
这个要顶 --------------------编程问答-------------------- mark,下次接着看,楼下继续~~ --------------------编程问答-------------------- 是不是和下面的有点像:
一次循环:
先生成第一个,和301比较,如果<301,继续生成,...直到第m个数,m<27且1+...+m>301时,此次循环结束
生成第二个:....
可能效率上比较慢吧,一直在比较...
--------------------编程问答--------------------
没有比这个更优秀的了.
数学真是神奇 --------------------编程问答--------------------
这两个算法是一致的.
28个点,总长度就是每个两个点的和 --------------------编程问答-------------------- 震荡不是真正意义上的随机,只能说是快速找到27个和为301的数字。 --------------------编程问答--------------------
很有点意思 --------------------编程问答-------------------- 先生成26个随机数,第27用结果值减去前面的合 ^_^ 不知道行不行 --------------------编程问答--------------------
这个实例化好 --------------------编程问答--------------------
public int HuoQu()
{
ArrayList arr=new ArrayList();
int q,p;
int w = 0;
Random ra = new Random();
q = ra.Next(0, 301);
p = 301 - q;
arr.Add(q);
for (int i = 0; i < 26;i++ )
{
if (i < 25)
{
q = ra.Next(0, p);
p = p - q;
}
else
{
q = ra.Next(1, p);
}
arr.Add(q);
}
foreach(int a in arr)
{
w += a;
}
return w;
}
乱写了一个。。貌似能达到效果。 --------------------编程问答-------------------- 不过有10几个0啊。 --------------------编程问答-------------------- --------------------编程问答-------------------- 24,29,39楼 是我见过的最奇妙的算法。。。
Perfect! --------------------编程问答-------------------- 学习呀
看得越多越觉得自己智商不行. --------------------编程问答-------------------- 1。初始化27的数组,0位和26位分别为0和301
2。随即在0-301之间生成25个随机数
3。数组排序
4。数组相邻两数分别相减,并赋值给新的26位数组,完成
--------------------编程问答-------------------- 我不知道是不是我电脑问题,只试出了1到100之间的随机数
class Random301
{
static void Main(string[] args)
{
int[] arryTemp=new int[27];
int[] arryRandom = new int[26];
//get random number,from 0 to 301
Random ran=new Random((int)DateTime.Now.Ticks);
arryTemp[0] = 0;
arryTemp[26] = 301;
for (int i = 1; i < 26; i++)
{
arryTemp[i] = ran.Next(0,301);
}
//sort the arry
int temp;
for (int m = arryTemp.Length-1; m > 0; m--) {
for (int n = 0; n < m;n++ ) {
if (arryTemp[m] < arryTemp[n]) {
temp=arryTemp[n];
arryTemp[n] = arryTemp[m];
arryTemp[m] = temp;
}
}
}
//get the lastest random arry
for (int j = 0; j < arryRandom.Length;j++) {
arryRandom[j] = arryTemp[j + 1] - arryTemp[j];
}
//check the arry
int sum = 0;
for (int k = 0; k < arryRandom.Length; k++) {
sum = sum + arryRandom[k];
}
Console.WriteLine(sum);
Console.ReadKey();
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
public void jk()
{
Random ran=new Random();
int sum = 0;
Console.WriteLine("请输入你要生成的随机数");
int q = Convert.ToInt32(Console.ReadLine());
int[] a = new int[q];
Console.WriteLine("他要等于多少");
int w = Convert.ToInt32(Console.ReadLine());
while (sum != w)
{
sum = 0;
for (int i = 0; i < q; i++)
{
a[i] = ran.Next(1,100);
sum += a[i];
}
}
for (int i = 0; i < q; i++)
{
Console.Write(a[i] + "\t");
}
Console.WriteLine("和为:{0}", sum);
}
static void Main(string[] args)
{
Program k = new Program();
k.jk();
}
}
} --------------------编程问答-------------------- 刚才也试乐下39楼的思路,耳目一新的感觉,不过感觉跑出来的数字比较平均:
1。初始化数组
2。将1随即加入数组,随即301次
--------------------编程问答--------------------
class Radom301Arry
{
static void Main(string[] args) {
int[] arryRandom = new int[26];
Random ran = new Random();
//add 1 301times into the arry
for (int i = 0; i <301;i++ ) {
arryRandom[ran.Next(0, 26)]++;
}
//chenck the arry
int sum = 0;
for (int j = 0; j < arryRandom.Length; j++) {
Console.WriteLine(arryRandom[j]);
sum = sum + arryRandom[j];
}
Console.WriteLine("sum:"+sum);
Console.ReadKey();
}
}
跟我想的一样,不过这样性能不好啊 --------------------编程问答--------------------
--------------------编程问答--------------------
static void Main(string[] args)
{
List<int> ps = new List<int>();
Random r = new Random();
for (int i = 0; i < 27; i++)
{
ps.Add(r.Next(301));
}
ps.Add(0);
ps.Add(301);
ps.Sort();
//int sum = 0;
for (int i = 1; i < ps.Count; i++)
{
//sum += ps[i] - ps[i - 1];
Console.Write(string.Format("{0} ", ps[i] - ps[i - 1]));
}
//Console.WriteLine();
//Console.Write(sum);
Console.ReadLine();
}
UP --------------------编程问答--------------------
x = random.Next(avg * 2); //生成随机数 震荡范围为 0 ~ 平均值*2
麻烦问一下这一行的目的是什么?我知道是生成avg平均值的两倍的区间内的数,可是为什么呢?不明白,求指教!!! --------------------编程问答-------------------- --------------------编程问答-------------------- 回 62 楼 没特别的含义 就是为了让随机数在平均值周围震荡。 --------------------编程问答-------------------- 思路:
1.随机生成 n-1 等于 m / n 的数
2.最后 last = m - ((n - 1)个随机数)
3.last + ((n - 1)个随机数) = m
注:因为前面 n - 1 个都是随机数, 那么第2步获得的结果也是随机数。
感觉像是个脑筋急转弯,也不知道自己思路对不对,各位见笑! --------------------编程问答-------------------- 楼上第一步是小于或者等于,改错了,晕 --------------------编程问答-------------------- using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Practice1
{
class Program
{
static void Main(string[] args)
{
int temp,sum = 0;
int[] a = new int[27];
Random random = new Random();
for (int i = 0; i <= a.Length-1; i++)
{
a[i] = random.Next(0, 301);
}
for(int i=0;i<=a.Length-1;i++)
{
for (int j = i; j <= a.Length -1;j++ )
if (a[i]>a[j])
{
temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
sum = a[0] + 301 - a[a.Length - 1];
Console.WriteLine("*****************************");
for (int j = 0; j < a.Length - 1; j++)
{
a[j] = a[j + 1] - a[j];
sum += a[j];
Console.WriteLine(a[j]);
}
Console.WriteLine("*****************************");
Console.WriteLine(sum);
Console.ReadKey();
}
}
} --------------------编程问答-------------------- 假设X轴上有M个线段,M个线段的总长度为N,那么我们所求的结果即为如何找到这M个线段在X轴上的位置。
我们设每一个线段的长度为L,那么很容易知道
L0+L1+L2+L3+..+LK+++LM=XM=N(点M在X轴上的横坐标)
那么如何找到这M个点在X轴上的坐标呢?
L0=X2-X1即第一个点的横坐标减去原点坐标
L1=X3-X2即第二个点的横坐标减去第一个点的横坐标
L2=X4-X3
....
LM=X(M)-X(M-1)
代码如下
public static int[] rand1(int c,int sum){
Random seed=new Random(sum);
int[] rs=new int[c];
int[] tmp=new int[c+1];
tmp[0]=0;
tmp[tmp.length-1]=sum;
for(int i=1;i<tmp.length-1;i++){
tmp[i]=seed.nextInt(sum);
}
Arrays.sort(tmp);
System.out.println(tmp);
for(int i=1;i<tmp.length;i++){
rs[i-1]=tmp[i+1]-tmp[i];
}
return rs;
} --------------------编程问答-------------------- 上述代码中
for(int i=1;i<tmp.length;i++){
rs[i-1]=tmp[i+1]-tmp[i];
}
处边界有问题,改为:
for(int i=1;i<tmp.length;i++){
rs[i-1]=tmp[i]-tmp[i-1];
} --------------------编程问答-------------------- 根据24#和41#的思路,写了个PHP的,感觉PHP操作更简单!呵呵!
--------------------编程问答-------------------- //思路取出27个随机数,按随机数占总随机数大小比率分配值,运算总数,随机27次,赋值54次,基本运算91次,性能应该可以
<?php
$b=301; //这个数字可以随便改
$arr=array();
$brr=array();
for($i=0;$i<26;$i++)
{
$one=mt_rand(1,$b-1);
$arr[]=$one;
}
array_push($arr,0,$b);
sort($arr);
foreach($arr as $k=>$v){
if($arr[$k+1]){
$brr[]=$arr[$k+1]-$arr[$k];
}
}
//brr就是结果数组,其和总是$b=301
?>
int sum=301;
int n = 301 / 26;
Random rand=new Random();
int cati=27;
Double[] arrary = new Double[27];
Double sumr = 0;
for (int i = 0; i < cati; i++)
{//
arrary[i] = rand.NextDouble();
sumr+= arrary[i];
//sum = sum - arrary[i];
// i*rand.next / 26
}
for (int i = 0; i < cati; i++)
{
arrary[i] = 301 * (arrary[i] / sumr);
}
foreach (int n1 in arrary)
{
Response.Write(","+n1);
} --------------------编程问答-------------------- 确实是有才啊。来学习是了。。。。。。
补充:.NET技术 , C#