给出二维矩阵的行数和列数
最初矩阵的所有元素均为0
给出每行应显示的1的数量
给出每列中应显示的1的数量
确定是否可以形成这样的矩阵。
示例:
Input: r=3 c=2 (no. of rows and columns)
2 1 0 (number of 1's that should be present in each row respectively)
1 2 (number of 1's that should be present in each column respectively)
输出:可能
说明:
1 1
0 1
0 0
我尝试通过检查Ri的总和= Ci的总和来解决这个问题,大约12个小时
但是我想知道
之类的情况是否不可能3 3
1 3 0
0 2 2
r和c最高为10 ^ 5
有什么想法我应该进一步发展吗?
编辑:添加的约束和输出只能是“可能”或“不可能”。可能的矩阵不需要显示。
现在有人可以帮我吗?
答案 0 :(得分:2)
提示:一种可能的解决方案是通过创建特殊图形并在其上运行标准最大流量算法来利用最大流量问题。
如果您不熟悉上述问题,则可以开始阅读有关该问题的信息,例如这里https://en.wikipedia.org/wiki/Maximum_flow_problem
如果您对完整的解决方案感兴趣,请发表评论,我将更新答案。但这需要理解上述算法。
解决方案要求
创建一个r+c+2
个节点的图形。
节点0是源,节点r+c+1
是宿。节点1..r
代表行,r+1..r+c
代表列。
创建以下边缘:
i=1..r
的节点r_i
i=r+1..r+c
到容量c_i
的汇聚i=1..r
和j=r+1..r+c
之间运行最大流量算法,行节点和列节点之间的饱和边定义应放置1的位置。
或者,如果不可能,则最大流量值小于矩阵中预期的流量值。
答案 1 :(得分:1)
(注意:为避免在谈论问题中的实际数字与谈论矩阵中的零之间的混淆,我将改为用空格填充矩阵和X。这显然不会改变问题。)
一些观察:
请记住,这是一种相当简单的方法:
(注意:我说要从需要最少X的行开始,然后一直到拥有最多X的行的原因是,需要更多X的行可能涉及检查更新数组和元素的更多元素的原因。这不仅需要推迟工作:只需减少X的行就可以帮助“合并”数组,从而减少了不同的列数,从而减少了X的工作量。在非常糟糕的情况下,例如在方矩阵的情况下,每一行都需要一个不同的正数X,而每一列都需要一个不同的正数X,最小到最大顺序意味着您可以在O(1)时间中处理每一行,总体上是线性时间,而最短到最后的顺序意味着每一行所花费的时间与其所需的X数量成正比,例如总体上是二次时间。)
总体而言,这不比O( r + c + n )时间(其中 n 是X的数量);我认为我列出的优化足以确保它更接近O( r + c )时间,但是很难百分百确定。我建议尝试一下,看看它是否足够快达到您的目的。
答案 2 :(得分:1)
我将通过一个例子来说明算法。
假设我们有m
行和n
列。令rows[i]
为i
行0 <= i < m
中1的数目,
并且cols[j]
是j
中0 <= j < n
列中1的数目。
例如,对于m = 3
和n = 4
,我们可以有:rows = {4 2 3}
,cols = {1 3 2 3}
和
解决方案数组为:
1 3 2 3
+--------
4 | 1 1 1 1
2 | 0 1 0 1
3 | 0 1 1 1
因为我们只想知道是否存在解决方案,所以rows
和cols
中的值可以按任何顺序排列。每个排列的解决方案就是上述解决方案的行和列的排列。
因此,给定rows
和cols
,按降序对cols
进行排序,对rows
进行升序。对于我们的示例,我们有cols = {3 3 2 1}
和rows = {2 3 4}
,以及同等的问题。
3 3 2 1
+--------
2 | 1 1 0 0
3 | 1 1 1 0
4 | 1 1 1 1
我们将cols
转换为更适合该算法的形式。 cols
告诉我们的是,我们有两个长度为3的1系列,一个长度为2的一系列1和一个长度为1的一系列1,它们将分布在数组的行中。我们重写cols
来捕获COLS = {2/3 1/2 1/1}
,即长度为3的2个序列,长度为2的1个序列和长度为1的1个序列。
因为我们有2个序列,长度为3,所以只有在第一行中可以放入两个1时,解决方案才存在。这是可能的,因为rows[0] = 2
。我们实际上并没有在第一行中放置任何1,而是通过减少长度为3的序列的长度来记录将1放置在其中的事实。因此COLS
变为:
COLS = {2/2 1/2 1/1}
,然后我们将两个计数合并为长度2的序列,得出:
COLS = {3/2 1/1}
我们现在有了减少的问题:
3 | 1 1 1 0
4 | 1 1 1 1
同样,我们需要从长度为2的序列中放入1s来解决。幸运的是,rows[1] = 3
我们可以做到。我们减少3/2
的长度,并得到:
COLS = {3/1 1/1} = {4/1}
我们有减少的问题:
4 | 1 1 1 1
这是由长度为1的4个系列解决的,这就是我们剩下的。如果在任何步骤上,COLS
中的序列都不能用于满足行数,则无法解决。
每行的一般处理可以描述如下。对于每行r
,从COLS
的第一个元素开始,根据需要减少count[k]/length[k]
的元素COLS
的长度,以使{{ 1}}等于count[k]
。在rows[r]
中消除长度为0的序列,并合并相同长度的序列。
请注意,由于COLS
的元素是按长度降序排列的,因此最后一个元素的长度减小后总是小于或等于COLS
中的下一个元素(如果存在下一个元素)。
示例2:存在解决方案。
COLS
长度2的1个序列递减以满足rows = {1 3 3}, cols = {2 2 2 1} => COLS = {3/2 1/1}
,而长度2的其他2个序列保持长度2。
rows[0] = 1
长度2的2个序列递减,长度1的1个序列递减。 长度已变为0的序列被删除,长度为1的序列被组合。
rows[0] = 1
COLS = {2/2 1/1 1/1} = {2/2 2/1}
可以满足rows[1] = 3
COLS = {2/1 1/0 1/1} = {2/1 1/1} = {3/1}
的解决方案。
rows[2]
示例3:解决方案不存在。
rows[2] = 3
COLS = {3/0} = {}
空间复杂度
很容易看出它是rows = {0 2 3}, cols = {3 2 0 0} => COLS = {1/3 1/2}
rows[0] = 0
COLS = {1/3 1/2}
rows[1] = 2
COLS = {1/2 1/1}
rows[2] = 3 => impossible to satisfy; no solution.
。
时间复杂度
我们仅对每一行进行一次迭代。对于每一行O(m + n)
,我们最多需要迭代一次
i
的{{1}}个元素。时间复杂度为rows[i] <= n
。
找到此算法后,我发现以下定理:
Havel-Hakimi定理(Havel 1955,Hakimi 1962)指出存在一个矩阵X 为0和1,行总和为a 0 =( a 1 ,a 2 ,…,a n )和列总计b 0 =(b 1 ,b 2 ,…,b m ),使得b i ≥b i + 1 对于每0 n-1,m 总计a 1 =(a 2 ,a 3 ,…,a n )和列总计b 1 =(b 1 −1,b 2 −1,...,b a1 −1,b a1 + 1 ,...,b m )也存在。
来自帖子Finding if binary matrix exists given the row and column sums。
这基本上是我的算法所做的,同时尝试优化递减部分,即上述定理中的所有 -1 。现在,我看到了上述定理,我知道我的算法是正确的。尽管如此,我还是通过将蛮力算法与最多50个细胞的阵列进行比较来检验算法的正确性。
这是C#实现。
COLS
答案 3 :(得分:0)
您可以使用蛮力(通过所有2^(r * c)
迭代)来解决它,但这将花费很长时间。如果r * c
小于64,则可以对64位整数使用按位运算将其加速到一定程度。但是,即使那样,在5亿年的时间里,以每秒1次尝试的速度遍历所有64位的可能性。
一个更明智的选择是一一添加位,并且仅在没有违反约束的情况下才继续放置位。这将消除绝大多数可能性,从而大大加快该过程。在backtracking中查找一般思路。这与通过猜测来解决数独没什么不同:一旦发现您的猜测错了,就将其删除,然后尝试猜测其他数字。
与数独一样,某些策略可以写入代码中,并在应用时会加速。例如,如果行中1的总和与列中1的总和不同,那么就没有解。
如果将打开超过50%的位,则可以解决互补问题(在更新行和列计数时,将所有的全都转换为零,反之亦然)。这两个问题是等价的,因为对一个问题的任何答案也对互补问题有效。
答案 4 :(得分:0)
可以使用Gale-Ryser Theorem在O(n log n)中解决此问题。 (其中n是两个度序列的长度的最大值)。
首先,通过在较小的序列上加0,使两个序列的长度相等,并将其长度设为n。
假设序列为A和B。以非降序对A排序,以非升序对B排序。为B创建另一个前缀和数组P,以使P的第i个元素等于B的第i个元素的和。
现在,将k从1迭代到n,然后检查
第二个和可以通过二进制搜索B中小于k的最后一个数字的索引然后使用预先计算的P在O(log n)中进行计算。
答案 5 :(得分:0)
从罗伯特·巴伦(RobertBaron)提供的解决方案中得到启发,我试图构建一种新算法。
rows = [int(x)for x in input().split()]
cols = [int (ss) for ss in input().split()]
rows.sort()
cols.sort(reverse=True)
for i in range(len(rows)):
for j in range(len(cols)):
if(rows[i]!= 0 and cols[j]!=0):
rows[i] = rows[i] - 1;
cols[j] =cols[j]-1;
print("rows: ",rows)
print("cols: ",cols)
#if there is any non zero value, print NO else print yes
flag = True
for i in range(len(rows)):
if(rows[i]!=0):
flag = False
break
for j in range(len(cols)):
if(cols[j]!=0):
flag = False
if(flag):
print("YES")
else:
print("NO")
在这里,我以升序对行进行排序,而cols以降序对行进行排序。如果需要放置1,则以后减少特定的行和列! 它适用于此处发布的所有测试用例!休息神知道