我在 A 列中有从第 1 行到第 12 行的数字列表,我需要将每行的数字分布在 Matlab 中的四个不同的列(列 B、C、D、E)以便: (i) B、C、D、E列所列值之和等于A列的值。 (二) 数值只能是整数。 (三) B、C、D、E栏的上限分别为10、10、5和5。 (四) B、C、D、E栏的最低限额分别为5、5、3、3。
也就是说,这些列中生成的值应与这些最大限制值相同。
例: |一 |乙 |C |D |
|17 | 6 | 5 | 3 | 3 |
有什么方法可以从 A 列中选取值,然后获取不同列 (B、C、D、E) 中的值,以便每行的总和等于 A?
我尝试过这样,但它仍然缺乏确切的目标。编码后提到了一些问题:
clear all
while true
A=randi([3 5],12,4);
if((sum(A,2)>=16) | (sum(A,2)<=30));
break;
end
end
disp(A);
disp(sum(A,2));
生成的所有值都是随机的,但它们介于 16 和 30 之间。但是最低值限制我无法理清BCDE该怎么做?如果我已经有 A 列的数据,那么如何使每行的 BCDE 值等于该总和?
不使用循环的快速和确定性方法。这个想法是首先将数字A
分成两半L
,R
。L
和R
的条件是它们位于[8 15]
之间。函数randSplit(x, lo, hi)
将执行此操作。
选择L = B + D
和R = C + E
。现在剩下的部分是两个拆分L
[B, D]
,R
拆分为[C, E]
;函数randSplit(x, lo, hi, LO, HI)
将执行此操作。在这种情况下的条件是B
,C
都位于[5 10]
和D
之间,E
都位于[3 5]
之间。
此方法速度很快,因为它每行输出矩阵正好调用 3 次randi
。
A = randi([16 30], 12,1);
mat = zeros(12,4);
for i = 1:12
[L, R] = randSplit(A(i), 8, 15); % L = B + D, R = C + E
[B, D] = randSplit(L, 3, 5, 5, 10);
[C, E] = randSplit(R, 3, 5, 5, 10);
mat(i,:) = [B C D E];
end
function [a, b] = randSplit(x, lo, hi, LO, HI)
if nargin == 3
a = randi([max(lo,x-hi) min(hi,x-lo)]);
b = x - a;
elseif nargin == 5
a = randi([max(LO,x-hi) min(HI,x-lo)]);
b = x - a;
end
end
示例输出:
[A mat] =
29 10 10 5 4
21 8 5 5 3
23 10 5 5 3
21 5 9 4 3
17 5 6 3 3
27 8 9 5 5
19 8 5 3 3
30 10 10 5 5
17 5 6 3 3
27 10 9 5 3
18 5 6 3 4
25 9 10 3 3
我建议你用一个简单的循环来做到这一点:
M = [0,0,0,0]; % A, B, C, D
For each A
While sum(M) is not A
M(A) = [(2 random numbers 5-10), (2 random numbers 3-5)]
end
end
使用randi
获取随机数。
这对于大数字/列表来说不是最佳的,但我相当确定对于您使用的数字来说足够快,除非您这样做数百万次。
我将把在 MATLAB 中实现这一点作为练习留给您。 :)如果你被卡住了,就大喊大叫。
<小时 />更新:
这又快又脏,但它:)它在tio.run上平均使用130毫秒。
A = 15+randi(15,12,1);
BCDE = zeros(numel(A),4);
temp = [0, 0, 0, 0];
for ii = 1:numel(A)
temp = [4+randi(6,1,2), 2+randi(3,1,2)];
while sum(temp) ~= A(ii)
temp = [4+randi(6,1,2), 2+randi(3,1,2)];
end
BCDE(ii,:) = temp;
end
[A, BCDE]
ans =
16 5 5 3 3
18 5 5 4 4
18 5 6 4 3
29 10 10 5 4
24 6 10 3 5
27 10 9 4 4
18 5 6 3 4
23 5 10 5 3
27 9 8 5 5
24 7 9 3 5
28 10 10 3 5
20 9 5 3 3