随机抽取n个和等于100的整数
Draw n random integers whose sum is equal to 100
伪代码示例:
Random function: (1 to 5, values less than 100, sum must be equal to 100 when all random numbers are added).
结果示例:
Number 1 = 35
Number 2 = 15
Number 3 = 10
Number 4 = 20
Number 5 = 20
你的问题不是很明确。有许多可能的解决方案,具有不同的属性。
这是我想到的第一个:通过选择 n[=,将区间 [0, 1] 细分为 n 个部分30=] − [0, 1] 中随机的 1 个点。然后将其缩放到 [0, A] 并使用这些子区间的长度作为您的 n 随机数,总和 A.
function GetRandomNumbers(ACount: Integer; const ASum: Double): TArray<Double>;
var
Itvs: TArray<Double>;
i: Integer;
begin
if ACount < 1 then
raise Exception.Create('GetRandomNumbers: Invalid parameters.');
// Create a subdivision of [0, 1]
SetLength(Itvs, ACount + 1);
Itvs[0] := 0;
for i := 1 to ACount - 1 do
Itvs[i] := Random;
Itvs[ACount] := 1;
TArray.Sort<Double>(Itvs);
SetLength(Result, ACount);
for i := 0 to ACount - 1 do
Result[i] := ASum * (Itvs[i + 1] - Itvs[i]);
end;
例如,这可能会给
16.7746451916173
7.29391833301634
22.1434036735445
3.25182809028775
50.5362047115341
对于 n = 5 和 A = 100。
这使用了类似于泛型的现代 Delphi 技术,但总体思路应该足够清晰,因此您可以在 Delphi 7 中实现它并使用您喜欢的任何排序方法。另外,我将把它作为练习来制作 GetRandomNumbers
.
的整数版本
仅使用整数和 Fisher-Yates 随机播放:
program cont3;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils;
const
SummandsCount = 5;
WantedSum = 100;
var
i, j, t, Cnt, WhereToInsert: integer;
JustNaturalNumbers: array[1..WantedSum] of Integer;
DividingPoints: array[0..SummandsCount] of Integer;
begin
Randomize;
Cnt := 1;
DividingPoints[0] := 0;
DividingPoints[SummandsCount] := 100;
for i := 1 to WantedSum - 1 do
JustNaturalNumbers[i] := i;
for i := WantedSum - 1 downto WantedSum - SummandsCount + 1 do begin
j := 1 + Random(i);
WhereToInsert := Cnt;
while (WhereToInsert > 1) and (JustNaturalNumbers[j] < DividingPoints[WhereToInsert-1]) do begin
Dec(WhereToInsert);
DividingPoints[WhereToInsert + 1] := DividingPoints[WhereToInsert]
end;
DividingPoints[WhereToInsert] := JustNaturalNumbers[j];
JustNaturalNumbers[j] := JustNaturalNumbers[i];
Inc(Cnt);
end;
t := 0;
for i := 1 to SummandsCount do begin
Writeln(DividingPoints[i] - DividingPoints[i-1]);
t := t + (DividingPoints[i] - DividingPoints[i-1]);
end;
Writeln('Sum = ', t);
Readln;
end.
输出示例:
22
4
7
18
49
Sum = 100
伪代码示例:
Random function: (1 to 5, values less than 100, sum must be equal to 100 when all random numbers are added).
结果示例:
Number 1 = 35
Number 2 = 15
Number 3 = 10
Number 4 = 20
Number 5 = 20
你的问题不是很明确。有许多可能的解决方案,具有不同的属性。
这是我想到的第一个:通过选择 n[=,将区间 [0, 1] 细分为 n 个部分30=] − [0, 1] 中随机的 1 个点。然后将其缩放到 [0, A] 并使用这些子区间的长度作为您的 n 随机数,总和 A.
function GetRandomNumbers(ACount: Integer; const ASum: Double): TArray<Double>;
var
Itvs: TArray<Double>;
i: Integer;
begin
if ACount < 1 then
raise Exception.Create('GetRandomNumbers: Invalid parameters.');
// Create a subdivision of [0, 1]
SetLength(Itvs, ACount + 1);
Itvs[0] := 0;
for i := 1 to ACount - 1 do
Itvs[i] := Random;
Itvs[ACount] := 1;
TArray.Sort<Double>(Itvs);
SetLength(Result, ACount);
for i := 0 to ACount - 1 do
Result[i] := ASum * (Itvs[i + 1] - Itvs[i]);
end;
例如,这可能会给
16.7746451916173
7.29391833301634
22.1434036735445
3.25182809028775
50.5362047115341
对于 n = 5 和 A = 100。
这使用了类似于泛型的现代 Delphi 技术,但总体思路应该足够清晰,因此您可以在 Delphi 7 中实现它并使用您喜欢的任何排序方法。另外,我将把它作为练习来制作 GetRandomNumbers
.
仅使用整数和 Fisher-Yates 随机播放:
program cont3;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils;
const
SummandsCount = 5;
WantedSum = 100;
var
i, j, t, Cnt, WhereToInsert: integer;
JustNaturalNumbers: array[1..WantedSum] of Integer;
DividingPoints: array[0..SummandsCount] of Integer;
begin
Randomize;
Cnt := 1;
DividingPoints[0] := 0;
DividingPoints[SummandsCount] := 100;
for i := 1 to WantedSum - 1 do
JustNaturalNumbers[i] := i;
for i := WantedSum - 1 downto WantedSum - SummandsCount + 1 do begin
j := 1 + Random(i);
WhereToInsert := Cnt;
while (WhereToInsert > 1) and (JustNaturalNumbers[j] < DividingPoints[WhereToInsert-1]) do begin
Dec(WhereToInsert);
DividingPoints[WhereToInsert + 1] := DividingPoints[WhereToInsert]
end;
DividingPoints[WhereToInsert] := JustNaturalNumbers[j];
JustNaturalNumbers[j] := JustNaturalNumbers[i];
Inc(Cnt);
end;
t := 0;
for i := 1 to SummandsCount do begin
Writeln(DividingPoints[i] - DividingPoints[i-1]);
t := t + (DividingPoints[i] - DividingPoints[i-1]);
end;
Writeln('Sum = ', t);
Readln;
end.
输出示例:
22
4
7
18
49
Sum = 100