动手学深度学习V2每日笔记(卷积层)

news2024/9/23 17:13:53

本文主要参考沐神的视频教程 https://www.bilibili.com/video/BV1L64y1m7Nh/p=2&spm_id_from=333.1007.top_right_bar_window_history.content.click&vd_source=c7bfc6ce0ea0cbe43aa288ba2713e56d
文档教程 https://zh-v2.d2l.ai/

本文的主要内容对沐神提供的代码中个人不太理解的内容进行笔记记录,内容不会特别严谨仅供参考。

1.函数目录

1.1 python

python位置
元组加法操作2.2

1.2 torch

torch.nn位置
Conv2d2.3
stack2.3
cat2.3

2. 卷积神经网络

2.1 卷积层

卷积层将输入和核矩阵进行交叉相关运算,加上偏移后得到输出。核矩阵和偏移是可以学习的参数。核矩阵的大小是超参数。

  • 交叉相关VS卷积
  • 二维交叉相关
    y i , j = ∑ a = 1 h ∑ b = 1 w w a , b x i + a , j + b y_{i,j}=\sum_{a=1}^h\sum_{b=1}^ww_{a,b}x_{i+a,j+b} yi,j=a=1hb=1wwa,bxi+a,j+b
  • 二维卷积
    y i , j = ∑ a = 1 h ∑ b = 1 w w − a , − b x i + a , j + b y_{i,j}=\sum_{a=1}^h\sum_{b=1}^ww_{-a,-b}x_{i+a,j+b} yi,j=a=1hb=1wwa,bxi+a,j+b
  • 由于对称性,在实际使用中没有区别
  • 一维和三维交叉相关
  • 一维
    y i = ∑ a = 1 h w a , x i + a y_{i}=\sum_{a=1}^hw_{a,}x_{i+a} yi=a=1hwa,xi+a
  • 文本、语言、时序序列
  • 三维
    y i , j , k = ∑ a = 1 h ∑ b = 1 w ∑ c = 1 d w a , b , c x i + a , j + b , k + c y_{i,j,k}=\sum_{a=1}^h\sum_{b=1}^w\sum_{c=1}^dw_{a,b,c}x_{i+a,j+b,k+c} yi,j,k=a=1hb=1wc=1dwa,b,cxi+a,j+b,k+c
  • 视频、医学图像、气象图像

2.1.1 二维互相关运算

def corr2d(X, K):
    """计算二维互相关运算"""
    h, w = K.shape
    Y = torch.zeros(X.shape[0]-h+1, X.shape[1]-w+1)
    for i in range(Y.shape[0]):
        for j in range(Y.shape[1]):
            Y[i,j] = (X[i:i+h, j:j+w]*K).sum()
    return Y

X = torch.arange(9).reshape(3,3)
K = torch.arange(4).reshape(2,2)

print(corr2d(X, K))

2.1.2 卷积层

class Conv2D(nn.Module):
    def __init__(self, kernel_size):
        super().__init__()
        self.weight = nn.Parameter(torch.rand(size=kernel_size))
        self.bias = nn.Parameter(torch.zeros(1))

    def forward(self, x):
        return corr2d(x, self.weight) + self.bias

2.1.3 完整代码

import torch
from torch import nn
from d2l import torch as d2l

def corr2d(X, K):
    """计算二维互相关运算"""
    h, w = K.shape
    Y = torch.zeros(X.shape[0]-h+1, X.shape[1]-w+1)
    for i in range(Y.shape[0]):
        for j in range(Y.shape[1]):
            Y[i,j] = (X[i:i+h, j:j+w]*K).sum()
    return Y

X = torch.arange(9).reshape(3,3)
K = torch.arange(4).reshape(2,2)

print(corr2d(X, K))
# 自定义卷积层
class Conv2D(nn.Module):
    def __init__(self, kernel_size):
        super().__init__()
        self.weight = nn.Parameter(torch.rand(size=kernel_size))
        self.bias = nn.Parameter(torch.zeros(1))

    def forward(self, x):
        return corr2d(x, self.weight) + self.bias
# 图像中目标的边沿检查
x = torch.ones((6,8))
x[:, 2:6] = 0
print(x)

k = torch.tensor([[1.0, -1.0]])
Y = corr2d(x, k)
print(Y)
# 学习卷积核
Conv2d = nn.Conv2d(1, 1, kernel_size=(1,2), bias=False)
x = x.reshape((1, 1, 6, 8))
Y = Y.reshape((1, 1, 6, 7))

for i in range(10):
    y_hat = Conv2d(x)
    l = (y_hat-Y)**2
    Conv2d.zero_grad()
    l.sum().backward()
    Conv2d.weight.data[:] -= 3e-2 * Conv2d.weight.grad
    if(i+1)%2 == 0:
        print(f'batch{i+1}, loss{l.sum():.3f}')

print(Conv2d.weight.data.reshape((1,2)))

2.2 填充和步幅

2.2.1 填充padding

在输入周围添加额外的行、列
在这里插入图片描述

  • 填充 p h p_h ph行和 p w p_w pw列,输出的形状为
  • ( n h − k h + p h + 1 ) ∗ ( n w − k w + p w + 1 ) (n_h-k_h+p_h+1)*(n_w-k_w+p_w+1) (nhkh+ph+1)(nwkw+pw+1)

2.2.2 步幅stride

  • 步幅是指行/列的滑动步长
  • 例如;高度3宽度2的步长
    在这里插入图片描述
    填充和步幅是卷积层的超参数
    填充在输入周围添加额外的行/列,来控制输出的形状
    步幅是每次滑动核窗口时的行/列的步长,可以成倍的减少输出形状

2.3.3 元组加法运算

a = (1, 1)
b = (8, 8)
print(a+b)

在这里插入图片描述
列表也具有相同的操作

a = [1, 1]
b = [8, 8]
print(a+b)

在这里插入图片描述

import torch
from torch import nn

def comp_conv2d(conv2d, X):
    X = X.reshape((1, 1) + X.shape)
    Y = conv2d(X)
    return Y.reshape(Y.shape[2:])

conv2d = nn.Conv2d(1, 1, kernel_size=3, padding=1)
X = torch.rand((8,8))
print(comp_conv2d(conv2d, X).shape)

conv2d = nn.Conv2d(1, 1, kernel_size=3, padding=1, stride=2)
print(comp_conv2d(conv2d, X).shape)

2.3 多输入输出通道

2.3.1 多个输入通道

  • 彩色图片可能有RGB三个通道
  • 转换为灰度会丢失信息
    在这里插入图片描述
    每个通道都有一个卷积核,结果是所有通道卷积结果的和
    在这里插入图片描述
    多个输入通道
输入X核W输出Y
c i ∗ n h ∗ n w c_i*n_h*n_w cinhnw c i ∗ k h ∗ k w c_i*k_h*k_w cikhkw m h ∗ m w m_h*m_w mhmw

Y = ∑ i 0 c i X i , : , : ∗ W i , : , : Y = \sum_{i_0}^{c_i}X_{i,:,:}*W_{i,:,:} Y=i0ciXi,:,:Wi,:,:
无论有多少输入通道,到目前为止我们只用到单输出通道。

def corr2d(X, K):
    """计算二维互相关运算"""
    h, w = K.shape
    Y = torch.zeros(X.shape[0]-h+1, X.shape[1]-w+1)
    for i in range(Y.shape[0]):
        for j in range(Y.shape[1]):
            Y[i,j] = (X[i:i+h, j:j+w]*K).sum()
    return Y

def corr2d_multi_in(X, K):
    return sum(corr2d(x,k) for x,k in zip(X, K))

X = torch.tensor([[[0.0,1.0,2.0],[3.0,4.0,5.0],[6.0,7.0,8.0]],[[1.0,2.0,3.0],
                [4.0,5.0,6.0],[7.0,8.0,9.0]]])
K = torch.tensor([[[0.0, 1.0],[2.0, 3.0]],[[1.0,2.0],[3.0,4.0]]])
print(corr2d_multi_in(X, K))

2.3.2 多个输出通道

我们可以有多个三维卷积核,每个核生成一个输出通道。

输入X核W输出Y
c i ∗ n h ∗ n w c_i*n_h*n_w cinhnw c o ∗ c i ∗ k h ∗ k w c_o*c_i*k_h*k_w cocikhkw c o ∗ m h ∗ m w c_o*m_h*m_w comhmw

Y = ∑ i 0 c i X i , : , : ∗ W i , : , :   f o r   i = 1 , . . . , c o Y = \sum_{i_0}^{c_i}X_{i,:,:}*W_{i,:,:} \ for\ i=1,...,c_o Y=i0ciXi,:,:Wi,:,: for i=1,...,co

  • 每个输出通道都可以识别特定模式
    在这里插入图片描述
  • 输入通道核识别并组合输入中的模式
def corr2d_multi_in_out(X, K):
    return torch.stack([corr2d_multi_in(X, k) for k in K], 0)

K = torch.stack((K, K+1, K+2), 0)
print(K.shape)
print(corr2d_multi_in_out(X,K))

2.3.3 1*1卷积层

k h = k w = 1 k_h=k_w=1 kh=kw=1是一个受欢迎的选择。它不识别空间模式,只是融合通道。
在这里插入图片描述
相当于输入形状为 n h n w ∗ c i n_hn_w*c_i nhnwci,权重为 c o ∗ c i {c_o*c_i} coci的全连接层。

2.3.4 nn.Conv2d()

nn.Conv2d 的作用是对输入的二维数据(如图像)进行卷积操作,输出经过卷积处理后的特征图。卷积操作可以帮助网络学习到数据的局部特征,如边缘、纹理等。

torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True, padding_mode='zeros')
  • 参数说明
  • in_channels (int): 输入数据的通道数。例如,对于RGB图像,in_channels 应为 3。
  • out_channels (int): 卷积层输出的通道数(即卷积核的数量)。
  • kernel_size (int or tuple): 卷积核的大小。如果是整数,则表示卷积核是正方形的;如果是元组,则表示卷积核的高度和宽度。
  • stride (int or tuple, 可选): 卷积核的步幅。默认值为 1
  • padding (int, tuple or str, 可选): 输入数据的填充。默认值为 0
  • dilation (int or tuple, 可选): 卷积核元素之间的间距。默认值为 1
  • groups (int, 可选): 控制输入和输出通道的连接。默认值为 1
  • bias (bool, 可选): 如果设置为 True,将会给输出添加一个可学习的偏置。默认值为 True
  • padding_mode (str, 可选): 填充模式。可选值为 ‘zeros’, ‘reflect’, ‘replicate’ 或 ‘circular’。默认值为 ‘zeros’
    输出张量的形状可以通过以下公式计算:
  • input: ( N , C i n , H i n , W i n ) (N,C_{in},H_{in},W_{in}) (N,Cin,Hin,Win)
  • output: ( N , C o u t , H o u t , W o u t ) (N,C_{out},H_{out},W_{out}) (N,Cout,Hout,Wout)
    H o u t = H i n + 2 ∗ p a d d i n g [ 0 ] − d i l a t i o n [ 0 ] ∗ ( k e r n e l _ s i z e [ 0 ] − 1 ) s t r i d e [ 0 ] H_{out}=\frac{H_{in}+2*padding[0]-dilation[0]*(kernel\_{size}[0]-1)}{stride[0]} Hout=stride[0]Hin+2padding[0]dilation[0](kernel_size[0]1)
    W o u t = H i n + 2 ∗ p a d d i n g [ 1 ] − d i l a t i o n [ 1 ] ∗ ( k e r n e l _ s i z e [ 1 ] − 1 ) s t r i d e [ 1 ] W_{out}=\frac{H_{in}+2*padding[1]-dilation[1]*(kernel\_{size}[1]-1)}{stride[1]} Wout=stride[1]Hin+2padding[1]dilation[1](kernel_size[1]1)
import torch
import torch.nn as nn

# 创建一个 Conv2d 对象
conv_layer = nn.Conv2d(in_channels=3, out_channels=16, kernel_size=3, stride=1, padding=1)

# 打印 Conv2d 对象的参数
print(conv_layer)

# 创建一个随机输入张量,形状为 (batch_size, in_channels, height, width)
input_tensor = torch.randn(1, 3, 32, 32)

# 通过卷积层前向传播输入张量
output_tensor = conv_layer(input_tensor)

# 打印输出张量的形状
print(output_tensor.shape)

在这里插入图片描述
对上述示例输出形状计算:

  • 输入张量形状(1,3,32,32)
  • 卷积核大小为3*3
  • 步幅为1
  • 填充为1
    输出高度
    H o u t = 32 − 2 ∗ 1 + 3 − 1 1 = 32 H_{out}=\frac{32-2*1+3-1}{1}=32 Hout=13221+31=32
    输出宽度
    W o u t = 32 − 2 ∗ 1 + 3 − 1 1 = 32 W_{out}=\frac{32-2*1+3-1}{1}=32 Wout=13221+31=32

2.3.5 stack

torch.stack 是 PyTorch 中的一个函数,用于沿新维度连接一系列张量。它的作用类似于 torch.cat,但不同的是,torch.cat 是在现有维度上进行连接,而 torch.stack 会在指定的维度上插入一个新的维度,然后在这个新维度上进行连接。

torch.stack(tensors, dim=0)

参数

  • tensors (sequence of Tensors): 要连接的张量序列。
  • dim (int): 新插入维度的索引位置。默认值为 0。
Tensor1.shapeTensor2.shapedimout
(3,3)(3,3)0(2,2,3)
(3,3)(3,3)1(3,2,3)
(3,3)(3,3)2(3,3,2)

沿着维度0进行stack

import torch

# 创建两个相同形状的张量
x = torch.arange(9).reshape(3,3)
y = torch.randn(3,3)
# 沿着0维度
z = torch.stack([x,y],0)
z
tensor([[[ 0.0000,  1.0000,  2.0000],
         [ 3.0000,  4.0000,  5.0000],
         [ 6.0000,  7.0000,  8.0000]],

        [[ 0.8259, -1.7941,  0.8862],
         [ 0.6030, -0.7413,  0.7847],
         [-0.0850,  0.7196, -0.7993]]])
z.shape
torch.Size([2, 3, 3])

沿着维度1进行stack

z1 = torch.stack((x,y),1)
z1
tensor([[[ 0.0000,  1.0000,  2.0000],
         [ 0.8259, -1.7941,  0.8862]],

        [[ 3.0000,  4.0000,  5.0000],
         [ 0.6030, -0.7413,  0.7847]],

        [[ 6.0000,  7.0000,  8.0000],
         [-0.0850,  0.7196, -0.7993]]])
z1.shape
torch.Size([3, 2, 3])

沿着维度2进行stack

z2 = torch.stack((x,y),2)
z2
tensor([[[ 0.0000,  0.8259],
         [ 1.0000, -1.7941],
         [ 2.0000,  0.8862]],

        [[ 3.0000,  0.6030],
         [ 4.0000, -0.7413],
         [ 5.0000,  0.7847]],

        [[ 6.0000, -0.0850],
         [ 7.0000,  0.7196],
         [ 8.0000, -0.7993]]])
z2.shape
torch.Size([3, 3, 2])

2.3.6 cat

torch.cat 是 PyTorch 中的一个函数,用于沿已有的维度连接一系列张量。与 torch.stack 不同的是,torch.cat 不会在连接过程中创建新的维度,而是直接在指定的维度上进行连接。

torch.cat(tensors, dim=0)
  • 参数
  • tensors (sequence of Tensors): 要连接的张量序列,这些张量在除 dim 维之外的其他维度上必须具有相同的形状。
  • dim (int): 指定在该维度上连接张量。默认值为 0。
Tensor1.shapeTensor2.shapedimout
(3,3)(3,3)0(6,3)
(3,3)(3,3)1(3,6)

沿着维度0进行cat

c0 = torch.cat((x,y),0)
c0
tensor([[ 0.0000,  1.0000,  2.0000],
        [ 3.0000,  4.0000,  5.0000],
        [ 6.0000,  7.0000,  8.0000],
        [ 0.8259, -1.7941,  0.8862],
        [ 0.6030, -0.7413,  0.7847],
        [-0.0850,  0.7196, -0.7993]])
c0.shape
torch.Size([6, 3])

沿着维度1进行cat

c1 =torch.cat((x,y),1)
c1
tensor([[ 0.0000,  1.0000,  2.0000,  0.8259, -1.7941,  0.8862],
        [ 3.0000,  4.0000,  5.0000,  0.6030, -0.7413,  0.7847],
        [ 6.0000,  7.0000,  8.0000, -0.0850,  0.7196, -0.7993]])
c1.shape
torch.Size([3, 6])

2.3.7 完整代码

import torch
from torch import nn

def comp_conv2d(conv2d, X):
    X = X.reshape((1, 1) + X.shape)
    Y = conv2d(X)
    return Y.reshape(Y.shape[2:])

conv2d = nn.Conv2d(1, 1, kernel_size=3, padding=1)
X = torch.rand((8,8))
print(comp_conv2d(conv2d, X).shape)

conv2d = nn.Conv2d(1, 1, kernel_size=3, padding=1, stride=2)
print(comp_conv2d(conv2d, X).shape)

def corr2d(X, K):
    """计算二维互相关运算"""
    h, w = K.shape
    Y = torch.zeros(X.shape[0]-h+1, X.shape[1]-w+1)
    for i in range(Y.shape[0]):
        for j in range(Y.shape[1]):
            Y[i,j] = (X[i:i+h, j:j+w]*K).sum()
    return Y

def corr2d_multi_in(X, K):
    return sum(corr2d(x,k) for x,k in zip(X, K))

X = torch.tensor([[[0.0,1.0,2.0],[3.0,4.0,5.0],[6.0,7.0,8.0]],[[1.0,2.0,3.0],
                [4.0,5.0,6.0],[7.0,8.0,9.0]]])
K = torch.tensor([[[0.0, 1.0],[2.0, 3.0]],[[1.0,2.0],[3.0,4.0]]])
print(corr2d_multi_in(X, K))

def corr2d_multi_in_out(X, K):
    return torch.stack([corr2d_multi_in(X, k) for k in K], 0)

K = torch.stack((K, K+1, K+2), 0)
print(K.shape)
print(corr2d_multi_in_out(X,K))

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1976516.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

3.OpenFeign与负载均衡

文章目录 什么是 OpenFegin0penFeign 与 Ribbon.对 consumer 的改造超时配置请求响应的压缩设置选择远程调用的底层实现技术OpenFegin 整合 LoadBalancer 负载均衡负载均衡策略的更换小结 前面消费者对于微服务的消费是通过 RestTemplate 完成的,这种方式的弊端是很明显的:消费…

清华计算几何-算法LowBound和ConvexHull(凸包)-GrahamScan

算法复杂度最低界限LowBound 算法求解复杂度是否存在一个最低界限,有时候想尽一切办法优化一个算法,去优化其复杂度,比如 清华计算几何-ConvexHull(凸包)-求极点InTriangle/ToLeft Test-CSDN博客 清华计算几何-ConvexHull(凸包)-求极边_计…

5.0-软件工程基础知识-考点分析

考试占比大概10分 软件工程概述软件过程模型 瀑布模型 瀑布模型变种-V模型 演化模型-原型模型 增量模型 喷泉模型 基于构件的开发模型 形式化方法模型需求分析系统设计系统测试运维软件质量和度量项目管理系统分析与设计概念结构化分析WebApp设计与用户界面设计

【小技巧】Keil5 和 NotePad++ 代码格式化 (Ctrl + Q) ( 插件安装astyle-3.5-x64 / NppAStyle)

Artistic Style 是适用于 C、C、C/CLI、 Objective-C 、C# 和 Java 编程语言的源代码缩进器、格式化器和美化器。它用 C 编写,可以从命令行使用,也可以作为库合并到另一个程序中。可以从命令行或选项文件输入选项。可以从用 C 以外的语言编写的程序中调用…

【qiankun微前端】基座主应用(vue2)+多个微应用(任意框架)

前言 前段时间对我们已有的工程进行了微前端改造,后来思考一下微前端的本质,查询了不少资料,从qiankun微前端示例中学到了不少。 微前端的核心,似乎应该是一个基座应用(含登录页,layout页,404和首页等),多个子应用(任意框架,提供内部页面内容),下面就对这个思路…

预警器件控制思考

预警器件控制思考 最小示例思想 当读取到环境信息与环境阈值的时候, 我们预警系统就要根据这些信息做出判断,是否要启动器件。 最简单的就是, 举温度temp的例子, temp(温度)与temp_th(阈值), 通过判断, 得出是否要启动器件. 如果在一段时间内, 一直是环境异常, 我…

私藏心术:低谷期翻身转运秘籍

私藏心术:低谷期翻身转运秘籍 在生活中,每个人都可能遇到低谷期,那些看似无法逾越的障碍和挫折。但记住,低谷期不是终点,而是重新站起来的起点。本文将分享一些实用的心术和策略,帮助你在低谷期实现翻身转…

第一个 Flask 项目

第一个 Flask 项目 安装环境创建项目启动程序访问项目参数说明Flask对象的初始化参数app.run()参数 应用程序配置参数 安装环境 mkvirtualenv flask_envpip install flask创建项目 启动程序 访问项目 http://127.0.0.1:5000/ 参数说明 Flask是一个用Python编写的轻量级Web应…

程序员学长 | 快速学习一个算法,CLIP

本文来源公众号“程序员学长”,仅用于学术分享,侵权删,干货满满。 原文链接:快速学习一个算法,CLIP 今天给大家介绍一个强大的算法模型,CLIP。 CLIP (Contrastive Language–Image Pre-training) 是一个…

机器学习流程图

第一部分:课程使用的技术栈 (1)Numpy 科学计算基础库,矩阵运算,线性代数 (2)matplotlib 绘图库,数据可视化 (3)Scikit 封装了各种分类,回归…

【课程总结】day19(下):Transformer源码深入理解

前言 在上一章【课程总结】day19(下):Transformer架构及注意力机制了解总结中,我们对Transformer架构以及注意力机制有了初步了解,本章将结合《The Annotated Transformer》中的源码,对Transformer的架构进行深入理解。 背景 《The Annotated Transformer》是由 Harva…

LaneATT推理详解及部署实现(上)

目录 前言1. 概述2. 环境配置3. Demo测试4. ONNX导出初探5. ONNX导出优化6. ONNX导出总结结语下载链接参考 前言 最近想关注下车道线检测任务,在 GitHub 上找了一个模型 LaneATT,想通过调试分析 LaneATT 代码把 LaneATT 模型导出来,并在 tens…

Java游戏源码:象棋网络对战版

学习java朋友们,福利来了,今天小编给大家带来了一款象棋网络对战版源码。 源码搭建和讲解 源码分为客户端和服务器,采用java原生 java.net.Socket 实现,服务器主循环代码: import java.net.ServerSocket; import jav…

二维码生成原理及解码原理

☝☝☝二维码配图 二维码 二维码(Quick Response Code,简称QR码)是一种广泛使用的二维条形码技术,由日本公司Denso Wave在1994年开发。二维码能有效地存储和传递信息,广泛应用于商品追溯、支付、广告等多个领域。二维…

Star-CCM+负体积网格检查与出现原因

要使网格可用于有限体积计算,每个网格单元必须具有正体积,否则初始化过程将失败,且模拟计算无法运行。 负体积网格单元可能会以多种不同的方式出现,但必须修复或从网格中移除,才能继续执行任何后续操作。 要检查体网…

<数据集>人员摔倒识别数据集<目标检测>

数据集格式:VOCYOLO格式 图片数量:8605张 标注数量(xml文件个数):8605 标注数量(txt文件个数):8605 标注类别数:1 标注类别名称:[fall] 序号类别名称图片数框数1fall860512275 使用标注工具&#xf…

当前生物信息学研究面临的四大机遇和挑战(特别是最后一个,一定要足够重视)...

生物信息学是应用计算方法分析生物数据,如 DNA,RNA,蛋白质和代谢物。生物信息学已成为促进我们对生命科学的理解以及开发新的诊断,治疗和生物技术产品的重要工具。本文我们将探讨生物信息学研究的一些当前趋势和发展,以…

如何快速入门 PyTorch ?

PyTorch是一个机器学习框架,主要依靠深度神经网络,目前已迅速成为机器学习领域中最可靠的框架之一。 PyTorch 的大部分基础代码源于 Ronan Collobert 等人 在 2007 年发起的 Torch7 项目,该项目源于 Yann LeCun 和 Leon Bottou 首创的编程语…

【C++题解】1249. 搬砖问题

欢迎关注本专栏《C从零基础到信奥赛入门级(CSP-J)》 问题:1249. 搬砖问题 类型:嵌套穷举 题目描述: 36 块砖, 36 人搬。男搬 4 ,女搬 3 ,两个小儿抬一砖。 要求一次全搬完。问需…

GitHub最全中文排行榜开源项目,助你轻松发现优质资源!

文章目录 GitHub-Chinese-Top-Charts:中文开发者的开源项目精选项目介绍项目特点核心功能1. 热门项目榜单2. 详细项目信息 如何使用覆盖范围软件类资料类 GitHub-Chinese-Top-Charts:中文开发者的开源项目精选 在全球范围内,GitHub已经成为了…