【问题标题】:Combination of possible values in an array with multiple constraints in Matlab?Matlab中具有多个约束的数组中可能值的组合?
【发布时间】:2013-03-07 18:07:18
【问题描述】:

我有一个数组 B:

B=[1 2 3; 10 20 30 ; 100 200 300 ; 1000 2000 3000]

这样

B =

           1           2           3
          10          20          30
         100         200         300
        1000        2000        3000

我正在使用以下代码来查找低于某个值(约束)的这些变量之间的可能组合——在这种情况下为 2000:

A=[123; 323; 12 ; 421]
SA=sum(A)
V=cell(length(B),1);
n=1;
for k = 1:length(B)
    for idx = nchoosek(1:length(B), k)'
        B_subset = B(idx);
        if (SA + sum(B_subset) <= 2000)
            V(n)={B_subset(:)}; %store them in a cell
            n=n+1;
        end
    end
end

但是我没有按照我想要的方式组合它们。


目标:

从 B 中找出可能的组合与 SA 相加,使它们的总和小于 2000?


约束 1:

  • 数组B 中的每一行只能一次使用一个值。

例如,这是可接受的:[1 2 20] [2 20 30]
这是正确之一:[1 20 100] [3 200 3000]


约束 2: - 答案应仅存储在单元格 V 中的一列中(如上面代码中初始化的那样)。

该单元格的输出应该与我当前的输出类似:

V = 

    [       100]
    [       300]
    [       200]
    [2x1 double]
    [2x1 double]
    [2x1 double]
    [3x1 double]

【问题讨论】:

  • V的内容可以吗?您只需要输出格式吗?
  • 我将用 V 的外观更新问题
  • V 看起来有点眼熟 :) 将更新答案。

标签: arrays matlab constraints combinations


【解决方案1】:

稍微更改了您的代码并在下面添加了一个测试 - 如果 V 未更改 -> 没有组合 -> 显示。已编辑以允许将其保存到元胞数组 V 并同时构造一个用于打印的字符串。

此代码考虑 B 中三个元素的每种组合,其中每个元素来自不同的列。

V=cell(length(B),1);
A=[123; 323; 12 ; 421];
SA=sum(A);
S = 'possible combinations :';
n = 1
for ii=1:4
    for jj=1:4
        if jj == ii
            continue
        end
        for kk=1:4
            if or(kk == jj,kk == ii)
                continue
            end
            B_subset = [B(ii,1), B(jj,2), B(kk,3)];
            if (SA + sum(B_subset) <= 2000)
                S = [S, ' ', mat2str(B_subset)];
                V{n} = B_subset;
                n += 1;
            end
        end
    end
end

if V == 'possible combinations :'
    disp('No possible combinations found')
else
    disp(S)
end

编辑:为问题的新部分添加答案。在最里面的循环中计算包含行的不同组合。

V = {}
for ii=1:3
    for jj=1:3
        for kk=1:3
            for ll = 1:3
                rows = [ii, jj, kk, ll]
                if isequal(rows, unique(rows))
                    % loop for turning off individual elements
                    result = [B(1,ii), B(2,jj), B(3,kk), B(4,ll)]
                    for mm = 0:1:15
                        % make a binary string - will loop through all combinations of zeros and ones
                        str1 = dec2bin(mm,4)
                        mask = zeros(1,4)
                        for nn = 1:4 % make a numeric vector
                            mask(nn) = str2num(str1(nn))
                        end
                        masked_result = mask.*result
                        V = [V {masked_result}]
                    end
                end
            end
        end
    end
end

【讨论】:

  • 代码仍然使用同一行的值,例如100 200 3010 200 30
  • 您说每列中的一个值:这是通过三个循环完成的。然后你说每行只有一个值 - 这是用 continue 完成的。它不能做到100 200 30,因为jjii 将是相同的,它会在检查答案之前继续。 V 中有旧值,因为它没有再次初始化。我已经更新了答案,也将整个 B 的循环更改为 4。
  • @NLed:我不明白你想要什么。每个可行的答案都是一个 1x3 矩阵。为什么有4个元素?此外,您是否还想打印超过 2000 个的答案,甚至是共享一行或一列的组合?
  • 嗯。我想我知道你想要什么,但这是大量的结果 - 似乎超过 60 个。不太知道该怎么做。还在想:)
  • 看,我已经尽力了。你的要求很奇怪,很难理解。另外,我认为这个问题不会帮助其他任何人——所以我们在这里乱扔垃圾。请尝试自己做一些事情,特别是尝试理解代码的作用。 Matlab 有一个出色的框架,用于在每行代码之后运行脚本和检查值。我真的建议你试试。您可以直接从 Matlab 的文本编辑器运行脚本。
【解决方案2】:

在这里,这个修复应该可以解决问题:

SA = sum(A);
V = cell(numel(B), 1);                  % // Changed 'length' to 'numel'
n = 1;
for k = 1:size(B, 1)                    % // Changed 'length' to 'size'
    for idx = nchoosek(1:numel(B), k)'  %'// Changed 'length' to 'numel'

        %// Ignore the combination if there are two elements from the same row
        rows = mod(idx, size(B, 1));
        if ~isequal(rows, unique(rows))
            continue
        end

        B_subset = B(idx);
        if (SA + sum(B_subset) <= 2000)
            V(n) = {B_subset(:)};
            n = n + 1;
        end
    end
end

也许它不是最有效的解决方案,但它很短而且很有效。

【讨论】:

  • 例如,~isequal 是什么意思?在检查它们是否是可行的组合之前,这段代码如何遍历不同的行/列?
  • @NLed numel 表示元素的数量 - 在本例中为 4x3=12。 ~ 在 matlab 中是否定的,所以这 ~isequal 表示如果 rows 不等于 unique(rows) - 当 rows 中有重复的元素时会发生这种情况
  • @EitanT 我已将您的代码用于另一个问题,也许您会感兴趣。 stackoverflow.com/questions/15284999/…
  • @NLed 此代码是否解决了此问题中描述的问题?
  • @EitanT 是的,我现在实际上正在使用您的代码,只是进行了一些细微的调整,我非常感谢。如果您有兴趣了解它的外观,请告诉我。
猜你喜欢
  • 1970-01-01
  • 2015-10-15
  • 2012-11-09
  • 1970-01-01
  • 1970-01-01
  • 2019-04-27
  • 1970-01-01
  • 2020-03-19
  • 1970-01-01
相关资源
最近更新 更多