LCP 22. 黑白方格画
一、题目描述
已知:画板上有 n * n 的网格。绘画规则为,可以选择任意多行以及任意多列的格子涂成黑色(选择的整行、整列均需涂成黑色),所选行数、列数均可为 0。
要求:最终的成品上需要有 k 个黑色格子,请返回共有多少种涂色方案。
注意:两个方案中任意一个相同位置的格子颜色不同,就视为不同的方案。
限制: 1 <= n <= 6
0 <= k <= n * n
原题链接:黑白方格画
二、问题分析
设网格上已经涂了 x 行 y 列,考虑到行列之间有一个重复格子,因此网格上的黑格子数目为 n*(x+y) - x*y。
即求解下列方程式,可能的(x, y)有多少种
n*(x+y) - x*y = k
由于 1 <= n <= 6 并且 0 <= x, y <= n
所以可以暴力穷举,计算得到可能的 (x,y) 值。
进一步,由于涂的行/列可以在 n 行/列中自由进行选择,
所以涂色的方案总共有:
C(n, x) * C(n, y)
三、数据结构及算法分析
1.数据结构
无
2.涉及算法
主要是 C(n, x) 的计算如何用代码实现。
C(n, x) = [n * (n-1) *… (n-x+1)] / [1 * 2 *… x]
代码实现如下:
def get(n, a):
res = 1
for i in range(n, n-a, -1):
res *= i
for j in range(1, a+1):
res /= j
return res
时间复杂度:O(n)
空间复杂度:O(1)
四、总结
结题思路主要分为两个步骤:
一、穷举计算方程式 n*(x+y) - x*y = k,计算得到需要涂多少行和列
二、具体到涂网格的哪一行哪一列,根据组合排列的知识,计算可能有多少种涂色方案
五、完整源码
class Solution:
def paintingPlan(self, n: int, k: int) -> int:
if k in (0, n * n):
return 1
def get(n, a):
res = 1
for i in range(n, n-a, -1):
res *= i
for j in range(1, a+1):
res /= j
return res
ans = 0
for x in range(n):
for y in range(n):
if n*(x+y) - x*y == k:
ans += get(n, x) * get(n, y)
return int(ans)
时间复杂度:O(n2)
空间复杂度:O(1)
一 起 前 进 |