LCP 22.黑白方格画

题目简述

小扣注意到秋日市集上有一个创作黑白方格画的摊位。摊主给每个顾客提供一个固定在墙上的白色画板,画板不能转动。画板上有 n * n 的网格。绘画规则为,小扣可以选择任意多行以及任意多列的格子涂成黑色(选择的整行、整列均需涂成黑色),所选行数、列数均可为 0

小扣希望最终的成品上需要有 k 个黑色格子,请返回小扣共有多少种涂色方案。

注意:两个方案中任意一个相同位置的格子颜色不同,就视为不同的方案。

题解示例

示例 1:

输入:n = 2, k = 2

输出:4

解释:一共有四种不同的方案:
第一种方案:涂第一列;
第二种方案:涂第二列;
第三种方案:涂第一行;
第四种方案:涂第二行。

示例 2:

输入:n = 2, k = 1

输出:0

解释:不可行,因为第一次涂色至少会涂两个黑格。

示例 3:

输入:n = 2, k = 4

输出:1

解释:共有 2*2=4 个格子,仅有一种涂色方案。

数据范围

1 <= n <= 6
0 <= k <= n * n

标记难度

难度:简单
通过次数:8065
提交次数:24485
通过率:32.9%

问题解析

本题主要考察组合和阶乘。

假设选择涂黑i行、j列,那么此时黑色方块共有 i*n + j*n - i*j 块,其中 i*j 为行和列重合的块数。

而在n行中取i行、在n列中取j列,即数学中的组合数,其值可以分别为 n! / (i!(n-i)!)n! / (j!(n-j)!) ,这便涉及到阶乘的计算了。

要注意的是,当不涂或者涂满时,方法都只有一种。

python3代码

class Solution:
    def paintingPlan(self, n: int, k: int) -> int:
        if k == 0 or k == n*n:
            return 1
        result = 0
        for i in range(1, n):
            for j in range(1, n):
                if n*i + n*j - i*j == k:
                    result += math.factorial(n)/(math.factorial(i) * math.factorial(n-i))*math.factorial(n)/(math.factorial(j) * math.factorial(n-j))           
        return int(result)

其中,阶乘的求解可以用递归,也可以用循环,或者直接用库函数,可以分别运行来比较其时间复杂度和空间复杂度。

另外,组合的求解方式也非常多样化,可以利用阶乘函数计算,也可以直接进行数值计算。

# 递归
def factorial(n):
	if n == 1:
		return 1
	else:
		return n * factorial(n-1)

# 循环
def factorial(n):
	fact = 1
	for i in range(2, n+1):
		fact *= i
	return fact

# 利用阶乘
def C(n, a):
	return factorial(n)/(factorial(a) * factorial(n-a))
	
# 直接计算
def C(n, a):
	result = 1
    for i in range(n, n-a, -1):
   		result *= i
    for j in range(1, a+1):
        result /= j
    return result

# 防溢出防除不尽
def C(n, a):
	result = 1
	for i in range(1, a+1):
		result *= (n+1-i)/i
	return result    

C语言代码

int factorial(int n)
{
   	if(n == 1) 
	{ 	
		return 1;
	}
   	return n * factorial(n-1);
}
int C(int n, int a)
{
   	return factorial(n) / (factorial(a) * factorial(n-a));
}
int paintingPlan(int n, int k){
    int result = 0, i, j;
    if(k == 0 || k == n*n)
    {
    	return 1;
  	}
    for(i = 1; i <= n; ++i)
    {
        for{j = 1; j <= n; ++j)
        {
            if((n*i + n*j - i*j) == k)
            {
                result += C(n, i) * C(n, j);
            }
        }
    }
    return result;
}

C++代码(Copy)

class Solution {
public:
	//预处理组合数
    int C[10][10];
    void Init(){
        for(int i = 0; i < 10; i++){
            for(int j = 0; j <= i; j++){
                if(!j) C[i][j] = 1;
                else C[i][j] = C[i - 1][j - 1] + C[i - 1][j];
            }
        }
    }
    int paintingPlan(int n, int k) {
        if(k == 0) return 1;
        if(k < n) return 0;
        if(k == n * n) return 1;
        Init();
        int ans = 0;
        for(int i = 0 ; i <= n; i++){
            for(int j = 0; j <= n; j++){
                if(n * i + n * j - i * j == k){
                    ans += C[n][i] * C[n][j];
                }
            }
        }
        return ans;
    }
};

大佬专属代码

int paintingPlan(int n, int k)
{
	int p=0;
	if(k==0)
	    p=1;
	if(n==1)
	{
	    if(k==1)
	        p=1;
	}
	if(n==2)
	{
	    if(k==2)
	        p=4;
	    if(k==3)
	        p=4;
	    if(k==4)
	        p=1;
	}
	if(n==3)
	{
	    if(k==3)
	        p=6;
	    if(k==5)
	        p=9;
	    if(k==6)
	        p=6;
	    if(k==7)
	       p=18;
	    if(k==8)
	        p=9;
	    if(k==9)
	        p=1;
	}
	if(n==4)
	{
	    if(k==4)
	        p=8;
	    if(k==7)
	        p=16;
	    if(k==8)
	        p=12;
	    if(k==10)
	        p=48;
	    if(k==12)
	        p=44;
	    if(k==13)
	        p=32;
	    if(k==14)
	        p=48;
	    if(k==15)
	        p=16;
	    if(k==16)
	        p=1;
	}
    if(n==5)
    {
        if(k==5)
            p=10;
        if(k==9)
            p=25;
        if(k==10)
            p=20;
        if(k==13)
            p=100;
        if(k==15)
            p=20;
        if(k==16)
            p=100;
        if(k==17)
            p=200;
        if(k==21)
            p=150;
        if(k==19)
            p=200;
        if(k==20)
            p=10;
        if(k==25)
            p=1;
        if(k==24)
            p=25;
        if(k==23)
            p=100;
        if(k==22)
            p=100;
    }
    if(n==6)
    {
        if(k==36)
            p=1;
        if(k==35)
            p=36;
        if(k==34)
            p=180;
        if(k==33)
            p=240;
        if(k==32)
            p=405;
        if(k==31)
            p=72;
        if(k==30)
            p=612;
        if(k==28)
            p=450;
        if(k==27)
            p=400;
        if(k==26)
            p=180;
        if(k==24)
            p=630;
        if(k==21)
            p=240;
        if(k==20)
            p=225;
        if(k==18)
            p=40;
        if(k==16)
            p=180;
        if(k==12)
            p=30;
        if(k==11)
            p=36;
        if(k==6)
            p=12;
    }
    return p;
}

敲黑板!!!
排列、组合、阶乘的各种实现代码必须做到信手拈来,还要考虑其时间复杂度、空间复杂度、是否溢出、是否除不尽等!!!

凉梦空间

欢迎你进入我的个人博客网站参观交流:https://www.liangmeng.xyz

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

凉丶梦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值