Skip to content

Latest commit

 

History

History
 
 

1605.Find-Valid-Matrix-Given-Row-and-Column-Sums

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 

1605.Find-Valid-Matrix-Given-Row-and-Column-Sums

首先我们要知道,我们有n^2个元素要填,但是只有2n个约束(即行与列的和),所以这是一个欠定方程组,一定有无穷多个解。即使任意指定第一行的n个元素(再不违反约束的情况下),那么剩下的n^2-n个待定元素也一定会有相应合适的解。所以整体的策略是:可以任意填充第一个元素,然后更新约束,相应填充后面的元素。不断重复。

从一个例子入手:我们考虑一个3x3的矩阵,并且a+b+c==x+y+z

O O O | a
O O O | b
O O O | c
______
x y z

我们先考虑第一行怎么填?我们先不考虑大局观,仅就第一行而言,我们只需要任填3个数字,使得sum等于a。不过,我们还有三个约束:a[0][0]<=x, a[0][1]<=y, a[0][2]<=z,否则colSum就会溢出。那么根据这个一个等式约束和三个不等式约束,我们一定能填出这三个非负整数来吗?答案是肯定的。因为这三个不等式约束合并起来相当于a = a[0][0]+a[0][1]+a[1][1] <= x+y+z,而这个是通过题干中a+b+c==x+y+z所能保证的。

既然(满足上述的约束的)第一行的三个非负整数一定可以搞出来,那么我们具体设计什么策略去填写呢?可以搞一个贪心,即每个元素尽量填最大的:

a[0][0] = min(x,a);
a[0][1] = min(y,a-a[0][0]);
a[0][2] = a-a[0][0]-a[0][1];

注意第三个式子其实等价于:a[0][2] = min(z, a-a[0][0]-a[0][1]),这是因为a = a[0][0]+a[0][1]+a[0][2] <= a[0][0]+a[0][1]+z,故a-a[0][0]-a[0][1] <= z

此时我们解决了第一行,那么剩下来我们要处理的是一个2x3的矩阵,且已有b+c==x'+y'+z'

O O O | b
O O O | c
______
x'y'z'

其中x'=x-a[0][0], y'=y-a[0][1], z'=z-a[0][2]. 同理,我们依然可以填写出第二行的三个非负整数,满足a[1][0]+a[1][1]+a[1][2]==b并且a[1][0]<=x', a[1][1]<=y', a[1][2]<=z'.

那么我们就要只剩最后一行,且已有c = x*+y*+z*

O O O | c
______
x*y*z*

其中x*=x-a[0][0]-a[1][0], y*=y-a[0][1]-a[1][1], z*=z-a[0][2]-a[1][2]. 很想然,从colSum的角度来看,此时的这三个数的值已经确定了:a[2][0]=x*, a[2][1]=y*, a[2][2]=z*。但是,我们从rowSum的角度来看,还需要满足a[2][0]+a[2][1]+a[2][2]==c. 很幸运,这个约束是已经满足的!因为从最初的a+b+c = x+y+z,我们已经一步步推出了c = x*+y*+z*

综上所述,按照上面的贪心法去填写每个元素,最终一定能得到满足题意的矩阵。