【问题标题】:Matlab: construct a binary matrix satisfying horizontal and vertical constraintsMatlab:构造一个满足水平和垂直约束的二进制矩阵
【发布时间】:2018-01-27 02:05:16
【问题描述】:

我想启动一个 mxn 二进制矩阵。矩阵每一列的总和等于给定值 s(j),对于 j=1..n。另外,矩阵每一行的求和应该在给定的范围内:lhs是dl(i),rhs是du(i),对于i=1..m。

现在我只能随机生成二进制列,每个列的和等于该列的s(j),例如以下代码。

xij = zeros(m,n);
for j=1:n
    randRows=randperm(m); %a row vector containing a random permutation of the integers from 1 to m inclusive.
    rowsWithOne=randRows(1:sj(j)); %row indices having 1, and sum up to sj
    xij(rowsWithOne,j)=1;
end

但是,xij 通常不满足水平约束。我在想我应该创建一个矩阵首先满足行约束lhs(下界)dl(i),然后,列约束s(j),最后填充偏移量以满足rhs du(i),但我没有知道如何在 Matlab 中实现它。有没有创建 xij 的想法?

提前致谢。

【问题讨论】:

  • 实际上,了解您的真正约束在这里会有所帮助...
  • 一些示例 dldusj 和示例预期结果将是有益的。

标签: matlab


【解决方案1】:

首先要考虑几件事,主要是如果问题甚至可以在给定的约束条件下解决。首先,您必须检查 s(j) 的总和 sum(s) 是否大于下限约束的总和 sum(dl),并且还小于上限约束的总和 sum(du)

一个简单的 if 语句应该能够检查这一点。完成此操作后,以下代码应该是问题的一种解决方案,但考虑到问题的性质,可能不会有唯一的解决方案。

%initialize counters
x = 1;
y = 1;
%make sure the lower bounds are first satisfied
for k = 1:nrows
    while (dl(k) > 0)
        if (s(y) > 0)
            xij(k,y) = 1;
            dl(k) = dl(k)-1;
            du(k) = du(k)-1;
            s(y) = s(y)-1;
        end
        y = y+1;
    end
    y = 1;
end

%make sure the columns all add to their specified values
for k = 1:ncols
    while (s(k) > 0)
        if (xij(x,k) == 0 && du(x) > 0)
            xij(x,k) = 1;
            du(x) = du(x)-1;
            s(k) = s(k)-1;
        end
        x = x+1;
    end
    x = 1;
end

第一个 for 循环沿行添加 1,以使每行满足最小约束。下一个 for 循环沿列添加 1,这样每列加起来就是所需的值。第一个 for 循环中的 if 语句确保如果该列已达到其所需值,则不会添加 1,第二个 for 循环中的 if 语句确保不会将 1 添加到行这会使它超过该行的最大值。

为了跟踪1的数量,每次将1添加到相应的行时,du会降低1,同样,每次将1添加到所需的值s(j)都会减去1添加到xij 矩阵的该列。

【讨论】:

  • 感谢 J.Mel 的回复。它真的很适合我的需要。我的问题有很多可行的解决方案,但我只想创建一个可行的解决方案作为模型的初始输入。在您回答之前,我尝试了另一种方法,它也可以确定可行的解决方案。具体来说,根据随机生成的 xij,确定最大和最小行总和的行索引。然后,我迭代地交换这些索引处的 xij 元素,直到 xij 满足每行的 dl 和 du 的范围。我将粘贴下面的代码仅供您参考。再次感谢您的帮助
  • 当然可以。你下面的方法是我对这个问题的最初想法,但对我来说,代码流更难可视化。很好地让它发挥作用,对一个问题有多种解决方案总是很好!
【解决方案2】:
%Create an initial xij matrix, each column of which consists of a random binary xij sequence, but sum of ones in each column equals to sj
Init_xij = zeros(nShift,nCombo);
for j=1:nCombo
    randRows=randperm(nShift); %a row vector containing a random permutation of the integers from 1 to nShift inclusive.
    rowsWithOne=randRows(1:sj(j)); %row indices having 1, and sum up to sj
    Init_xij(rowsWithOne,j)=1;
end

%Adjust the initial xij matrix to make it feasible, satisfying horizontal
%LHS (dli) and RHS (dui) constraints
Init_xij_Feasible=Init_xij;
k=1;
while k
    RowSum=sum(Init_xij_Feasible,2); %create a column vector containing the sum of each row
    CheckLB=lt(RowSum,dli); %if RowSum <dli, true
    CheckUB=gt(RowSum,dui); %if RowSum >dui, true
    if ~any(CheckLB)&&~any(CheckUB) %if any element in CheckLB and CheckUB is zero
        break,
    else
        [~,RowIdxMin]=min(RowSum);
        [~,RowIdxMax]=max(RowSum);
        ColIdx=find(Init_xij_Feasible(RowIdxMax,:) & ~Init_xij_Feasible(RowIdxMin,:),1); % returns the first 1 column index corresponding to the nonzero elements in row RowIdxMax and zero elements in row RowIdxMin.
        %swap the min and max elements
        [Init_xij_Feasible(RowIdxMin,ColIdx),Init_xij_Feasible(RowIdxMax,ColIdx)]=deal(Init_xij_Feasible(RowIdxMax,ColIdx),Init_xij_Feasible(RowIdxMin,ColIdx));
    end 
k=k+1;
end

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-01
    • 2010-10-29
    • 1970-01-01
    相关资源
    最近更新 更多