如何确定是否可以构造具有给定行和列总和的二进制矩阵。
输入:
第一行输入包含两个数字1≤m,n≤1000,矩阵的行数和列数。下一行包含m个数字0≤ri≤n - 矩阵中每行的总和。第三行包含n个数字0≤cj≤m - 矩阵中每列的总和。
输出:
如果存在m-by-n矩阵A,则输出“YES”,每个元素为0或1.否则为“否”。
我尝试阅读有关断层扫描算法但无法找到答案,因为所有与断层扫描算法相关的论文都非常复杂。
有人可以帮帮我..
答案 0 :(得分:10)
我已经成功实现了使用基于network flow的建模为R随机生成这样的矩阵。我打算有一天写下这些想法,但还没有找到时间。为此重新研究,我在Miklós和Podani的Randomization of Presence–absence Matrices: Comments and New Algorithms中读到了:
Havel - Hakimi定理(Havel 1955,Hakimi 1962)表明存在矩阵 X n ,m 的0和1的行总计 a 0 =( a 1 , a 2 ,..., a n )和列总数 b 0 =( b 1 , b 2 , ..., b m ),以便 b i ≥ b i +1 每0 <&lt; i &lt; m 当且仅当另一个矩阵 X n -1, m 为0时和1的行总计 a 1 =( a 2 , a 3 ,..., a n )和列总计 b 1 =( b 1 -1, b 2 -1,..., b a 1 -1, b a 1 +1 ,..., b m )也存在。
我想这应该是以递归方式决定你的问题的最佳方法。
用我自己的话说:选择任何一行,将其从总计列表中删除。调用删除号码 k 。还要使用大的总和从 k 列中减去一个。您获得较小矩阵的描述,并递归。如果在任何时候您没有具有非零和的 k 列,则不存在这样的矩阵。否则,您可以使用反向过程递归地构建匹配矩阵:获取递归调用返回的矩阵,然后再添加一行 k ,并将其放置在您最初减去其中一个计数的列中。
bool satisfiable(std::vector<int> a, std::vector<int> b) {
while (!a.empty()) {
std::sort(b.begin(), b.end(), std::greater<int>());
int k = a.back();
a.pop_back();
if (k > b.size()) return false;
if (k == 0) continue;
if (b[k - 1] == 0) return false;
for (int i = 0; i < k; i++)
b[i]--;
}
for (std::vector<int>::iterator i = b.begin(); i != b.end(); i++)
if (*i != 0)
return false;
return true;
}