给定两个输入数组[R1,...,Rn]和[C1,...,Cn]。我们想要创建一个二进制矩阵A(大小为nxn),使得A的列i中的元素之和为Ci,并且A的行j中的元素之和为Rj。
我尝试使用贪婪算法填充:从左到右填充1并递减Ci并对每行执行此操作。但是,它没有用。 (另外,我尝试按递减顺序对行和列进行排序,但仍然没有工作)
答案 0 :(得分:6)
这可以使用最大流量来解决。 LightOJ上提供了类似(更难的版本)问题,我的代码为reference
这是解决方案。
我们将首先创建一个二分图。将行数设为no_rows
,列数为no_cols
。
现在创建no_rows + no_cols
个节点。安排左边的第一个no_rows
节点(这将形成我们的二分图的一个“副”)。让我们将这些节点编号为l1, l2, ..., lno_row
。
同样安排右边的最后no_cols
个节点(将形成第二个“partite”)。让这些编号为r1, r2, ... , rno_cols
。
现在为所有li
和rj
添加1 <= i <= no_rows
和1 <= j <= no_cols
之间的边
li
,从左到右,容量为1.
现在创建一个源(S)和一个接收器(T)。将从源定向的单位容量边缘添加到左侧的每个顶点。
类似地,将从右侧每个顶点定向的单位容量边缘添加到接收器。
现在只需在此图表中找到最大流量。现在,如果某个rj
和某些(i, j)
之间存在流,则表示单元格(S, l)
将为1,否则为0。
注意:为确保存在这样的二进制矩阵,请确保每个(r, T)
边和li
边都完全填满。
编辑:以下是C ++ ideone
中Dinic的实现编辑2:将源连接到任何Ri
的边的容量为R
(其中ri
是指示行总和的给定输入数组)。同样,连接T
到汇Ci
的边的容量为C
(其中const string baseUri = ""; // base url of API
const string setDealFlagUri = "Deals/SetDealFlag";
是输入中指定列总和的数组)