背包问题 总结详解

就是感觉之前 dp 的 blog 太乱了整理一下。


0-1 背包

例题:P1048

朴素算法

思路

对于一个物品,我们可以选,也可以不选。

我们用w_i表示第 i 件物品的重量,v_i表示第 i 件物品的价值。

考虑dp_{i,j}表示前 i 件物品放入容量为j的背包中的最大价值。

如果我们放不下第 i 件物品(把它打入冷宫),那么dp_{i,j}=dp_{i-1,j};否则入宫

然后发生了一场宫斗:dp_{i,j}=max(dp_{i-1,j},dp_{i-1,j-w_i}+v_i)

这就是0-1背包的状态转移方程。

Code
#include <bits/stdc++.h>
using namespace std;
int w[maxn],v[maxn];
//w[i]表示第i个物品的重量,v[i]是价值 
int dp[maxn][maxm];
//dp[i][j]表示前i个物品放入容量为j的背包里的最大值
int main(){int n,m;cin>>n>>m;//n是物品个数,m是背包大小for(int i=1;i<=n;i++)cin>>w[i]>>v[i];for(int i=1;i<=n;i++){for(int j=0;j<=m;j++){if(j<w[i])//放不下第i个物品 dp[i][j]=dp[i-1][j];//打入冷宫 else//入宫 dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+v[i]);//然后是场宫斗}}cout<<dp[n][m]<<endl;return 0;
}

滚动数组优化

显然,朴素算法的二维数组太耗费空间了。我们可以进行优化。

观察一下二维数组的代码,注意到 i跟个摆设似的,没啥用途。(注意力惊人)

因为dp_{i,j}只跟dp_{i-1,j}有关系,所以我们没必要记录 i。

不妨我们来试一试优化(试试就逝世)

#include <bits/stdc++.h>
using namespace std;
int w[maxn],v[maxn],dp[maxm];
int main(){int n,m;cin>>n>>m;for(int i=1;i<=n;i++)cin>>w[i]>>v[i];for(int i=1;i<=n;i++){for(int j=w[i];j<=m;j++)dp[j]=max(dp[j],dp[j-w[i]]+v[i]);}cout<<dp[m]<<endl;return 0;
}

乍一看没什么问题,实则喜提 0 分好成绩。

为什么呢?           dp_{j-w_i}更新的比dp_j早!

因此倒过来循环即可。

Code
#include <bits/stdc++.h>
using namespace std;
int w[maxn],v[maxn],dp[maxm];//w是重量,v是价值
int main(){int n,m;//n是物品个数,m是背包容量cin>>n>>m;for(int i=1;i<=n;i++)cin>>w[i]>>v[i];for(int i=1;i<=n;i++){for(int j=m;j>=w[i];i--)//这里注意了:由于如果正着循环,dp[j-w[i]]会比dp[i]更新的早,所以要倒过来循环 dp[j]=max(dp[j],dp[j-w[i]]+v[i]);}cout<<dp[m]<<endl;return 0;
}

完全背包

有N种物品和一个容量是M的背包,每种物品都有无限件可用。
第i种物品的体积是v[i],价值是w[i]。
求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值。

洛谷上找不到例题所以只能自己写了。

转 0-1 背包

完全背包和 0-1背包 的差别就是物品可以拿无限次。 所以考虑把完全背包转成 0-1背包。

我们可以想一下,物品有无限件,肯定是超过 M(背包容量)的

我们可以把每个物品拆分成\frac{M}{w_i}个小物品。这样就和 0-1 背包一样了。

拆分的代码:
int tot=0;//计算物品总数
for(int i=1;i<=n;i++){int a,b;//a是重量,b是价值cin>>a>>b;for(int j=1;j<=m/a;j++){w[++tot]=a;v[tot]=b;}
}
完整代码
#include <bits/stdc++.h>
using namespace std;
int w[maxn],v[maxn],dp[maxm];
int main(){int n,m;cin>>n>>m;int tot=0;//计算物品总数for(int i=1;i<=n;i++){int a,b;//a是重量,b是价值cin>>a>>b;for(int j=1;j<=m/a;j++){w[++tot]=a;v[tot]=b;}}for(int i=1;i<=tot;i++){for(int j=m;j>=w[i];j--)//倒着循环dp[j]=max(dp[j],dp[j-w[i]]+v[i]);}cout<<dp[m]<<endl;return 0;
}

完全背包自己的算法

这次我们不转 0-1背包。

由于至少放入一个,考虑最后一个放入的物品,其占用 w 的空间,价值是 v。

由于物品有无限多个,放入一个以后还是有无限多个,但是背包大小减少了 w。

问题转换为从前i个物品种选择一些物品放入j-w_i的背包中可以获得的最大价值。

由此推出状态转移方程:dp_{i,j}=max(dp_{i-1,j},dp_{i-1,j-k\times w_i}+k\times v_i)

我们用滚动数组,优化空间。和 0-1背包类似。

方程优化成这样:dp_j=max(dp_j,dp_{j-w_i}+v_i)

虽然它的状态转移方程和0-1背包的一样,但是它不用倒着循环,正着循环即可。

#include <bits/stdc++.h>
using namespace std;
//对于物品i,你可以把它打入冷宫(不选)或者让它入宫(选) 
//不过啊,这是无限背包,所以可以无限放 
//也就是说,你放完一个,还有无限个,但是呢背包的大小减少了w[i]
//因此问题转化为从前i个物品中选一些放入大小为j-w[i]的背包中可获得的最大价值
int w[maxn],v[maxn],dp[maxm];
int main(){int n,m;cin>>n>>m;for(int i=1;i<=n;i++)cin>>w[i]>>v[i];for(int i=1;i<=n;i++){for(int j=w[i];j<=m;j++)//这个正着循环即可dp[j]=max(dp[j],dp[j-w[i]]+v[i]); }cout<<dp[m]<<endl;return 0; 
}

转多重背包

没错,完全背包还可以转多重背包。不过建议读者先阅读下面的多重背包再看这个算法。

其实很简单。我们把多重背包里的s_i定义成\frac{m}{w_i}来求解就可以了。

状态转移方程:dp_{i,j}=max(dp_{i-1,j},dp_{i-1,j-k\times w_i}+k\times v_i)

最后是代码部分:

#include <bits/stdc++.h>
using namespace std;
int w[maxn],v[maxn],dp[maxm];
int main(){int n,m;cin>>n>>m;for(int i=1;i<=n;i++)cin>>w[i]>>v[i];for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){for(int k=0;k<=j/w[i];k++)dp[i][j]=max(dp[i][j],dp[i-1][j-k*w[i]]+k*v[i]);}}cout<<dp[n][m]<<endl;return 0;
}

当然,由于多重背包的朴素算法的复杂度是\Theta (N\times M\times K)的,所以必须优化(参见下面多重背包部分)。

多重背包

例题:P1776

朴素算法

多重背包 0-1背包 的差别就是 0-1背包 里一个物品只有一件,但多重背包里一个物品有s[i]件。

所以,我们分类讨论:

  1. s[i]*w[i]>=m 转完全背包
  2. 转0-1背包。拿一个 k 去枚举数量,于是问题变成了一个重量为k\times w,价值为k\times v的物品取不取

来人!上代码!

#include <bits/stdc++.h>
using namespace std;
int w[maxn],v[maxn],s[maxn],dp[maxm];
int main(){int n,m;cin>>n>>m;for(int i=1;i<=n;i++)cin>>w[i]>>v[i]>>s[i];for(int i=1;i<=n;i++){if(s[i]*w[i]>=m){//相当于完全背包(因为比背包容量m大) for(int j=w[i];j<=m;j++)dp[j]=max(dp[j],dp[j-w[i]]+v[i]); }else{//否则转0-1背包 for(int j=m;j>=w[i];j--){for(int k=s[i];k>=0;k--){//枚举数量 if(j>=k*w[i])dp[j]=max(dp[j],dp[j-k*w[i]]+k*v[i]);}}}}cout<<dp[m]<<endl;return 0;
}

显然,时间复杂度不是一般的高,是二般的高

所以优化是必须的。接下来我们来看多重背包的两种优化。

多重背包的二进制优化

思路

我们想一下,我们当时用k从s[i]枚举到0是否必要。

我们其实可以合并一些物品。

所以我们可以只枚举一些物品,通过这些物品互相合并,产生新的物品。比如:10=1+2+4+3

那为什么不拆成1+2+7呢?因为这样你就无法合成出4了。

那怎么枚举呢?这里要用到一点倍增的思想了。

给大家看一下局部代码:

int a,b,s;//a是重量,b是价值,s是数量
cin>>a>>b>>s;
//如何合成这些多余的物体
int k=1;
while(k<=s){w[++cnt]=k*a;//合成的重量v[cnt]=k*b;//合成的价值s-=k;//物品数相应减少k*=2;//翻倍
}
if(s){//没办法翻倍了w[++cnt]=s*a;v[cnt]=s*b;//剩下的自动合成
}

这样就OK了。

Code
//由于直接枚举取多少个会TLE
//所以我们进行二进制优化
//思考一下,其实我们没必要枚举0-s
//我们可以不断倍增:1,2,4,8,16,32,64,128...
//取这些数量个物品
//这样,通过不断组合可以组合出所有种类
//比如:10=1+2+4+3
//为什么有个3呢?
//因为正好剩个3了
//靠1,2,4,3可以组成0-10的所有数
//5=1+4 6=2+4 7=3+4 8=3+4+1 9=2+3+4 10=1+2+3+4
//所以在枚举时,我们不断倍增就可以了
//这样可以大大减少枚举量
#include <bits/stdc++.h>
using namespace std;
int w[maxn],v[maxn],dp[maxm];
int main(){int n,m;cin>>n>>m;int cnt=0;//记录新物体数(相当于优化后的n)for(int i=1;i<=n;i++){int a,b,s;//a是重量,b是价值,s是数量cin>>a>>b>>s;//接下来是重中之重//如何合成这些多余的物体int k=1;while(k<=s){w[++cnt]=k*a;//合成的重量v[cnt]=k*b;//合成的价值s-=k;//物品数相应减少k*=2;//翻倍}if(s){//没办法翻倍了w[++cnt]=s*a;v[cnt]=s*b;//剩下的自动合成}}//0-1背包for(int i=1;i<=cnt;i++){for(int j=m;j>=w[i];j--)dp[j]=max(dp[j],dp[j-w[i]]+v[i]);}cout<<dp[m]<<endl;return 0;
}

我个人认为这个方法好懂,好写,比下面的单调队列优化好一些。

单调队列优化多重背包

单调队列优化的思想就是给拿完后剩余体积分类,并且剩余体积一定不大于w,不然就能再拿。

我们可以枚举剩余体积,代码如下:

for(int i=1;i<=n;i++)          //->物品个数for(int j=0;j<w;j++)       //->剩余体积for(int k=j;k<=m;k+=w) //->不同个数

到这应该不难理解。

接下来,我们把这些状态表示一下:

dp_0dp_wdp_{2\times w} (剩余体积 0)
dp_1 dp_{w+1} dp_{2\times w+1} (剩余体积 1)
......
dp_jdp_{w+j}dp_{2*w+j}  (剩余体积 j)

于是,我们把问题分成 j 类,每类就是一个单调队列。

dp_i=dp_j
dp_{j+w}=max(dp_j+v,dp_{j+w})
......
dp_{j+k\times w}=max(dp_j+k\times v,dp_{j+w}+(k-1)\times v,......,dp_{j+k\times w})

我们把v提出来,就是:

dp_j=dp_j
dp_{j+w}=max(dp_j,dp_{j+w}-v)+v
dp_{j+2*w}=max(dp_j,dp_{j+w}-v,dp_{j+2\times w}-2\times v)+2\times v
......
dp_{j+k\times w}=max(dp_j,dp_{j+w}-v,dp_{j+2\times w}-2\times v, ... ,dp_{j+k\times w}-k\times v)+k\times v

所以,我们用一个队列维护最大值的下标,每次入队dp_{j+k\times w}-k\times w即可。

但是由于我们要进行比较,所以我们还需要一个 pre 数组维护上一轮的队列就OK啦。

//单调队列优化的思想就是给拿完后剩余体积分类
//剩余体积一定<w,不然就可以再装
//0,1,2,3,......,w-1
//怎么枚举呢?看代码:
//for(int i=1;i<=n;i++)          ->物品个数
//    for(int j=0;j<w;j++)       ->剩余体积
//        for(int k=j;k<=m;k+=w) ->不同个数
//我们把这些状态表示一下:
//dp[0] dp[w] dp[2*w] ...... (剩余体积0)
//dp[1] dp[w+1] dp[2*w+1] ...... (剩余体积1)
//......
//dp[j] dp[w+j] dp[2*w+j] ...... (剩余体积j)
//我们把问题分为j类,每类就是一个单调队列
//dp[j]=dp[j]
//dp[j+w]=max{dp[j]+v,dp[j+w]}
//......
//dp[j+k*w]=max{dp[j]+k*v,dp[j+w]+(k-1)*v,......,dp[j+k*w]}
//我们稍微变换一下:
//dp[j]=dp[j]
//dp[j+w]=max{dp[j],dp[j+w]-v}+v
//dp[j+2*w]=max{dp[j],dp[j+w]-v,dp[j+2*w]-2*v}+2*v
//......
//dp[j+k*w]=max{dp[j],dp[j+w]-v,dp[j+2*w]-2*v,......,dp[j+k*w]-k*v}+k*v
//相当于把价值v挪到max函数外了
//所以说,我们每次入队dp[j+k*w]-k*w,维护最大值即可
//que维护的是dp[j+k*w]-k*w最大值的下标
//pre维护的是上一次的que
//每次比较一下即可 
#include <bits/stdc++.h>
using namespace std;
const int maxm=40005;
int dp[maxm],pre[maxm],que[maxm];//que是队列 
int main(){int n,m;cin>>n>>m;for(int i=1;i<=n;i++){int w,v,s;cin>>w>>v>>s;memcpy(pre,dp,sizeof(dp));for(int j=0;j<w;j++){//j个单调队列,j枚举的是拿完后剩下的重量(最多剩w-1) int head=0,tail=-1;//头尾指针for(int k=j;k<=m;k+=w){//k是取(k-j)/w件物品的重量 if(head<=tail && k-s*w>que[head])head++;while(head<=tail && pre[que[tail]]-(que[tail]-j)/w*v<=pre[k]-(k-j)/w*v)tail--;if(head<=tail)dp[k]=max(dp[k],pre[que[head]]+(k-que[head])/w*v);que[++tail]=k;}}}cout<<dp[m]<<endl;return 0;
}

复习(混合背包)

Review

混合背包就是 0-1背包、完全背包、多重背包 的结合。

内容状态转移方程注意事项
0-1背包物品选/不选dp_j=max(dp_j,dp_{j-w_i}+v_i)倒着循环
完全背包物品无数件dp_j=max(dp_j,dp_{j-w_i}+v_i)正着循环
多重背包物品s_idp_j=max(dp_j,dp_{j-k\times w_i}+k\times v_i)优化
思路

混合背包还是输入w_i\: v_i\: s_i,分别表示重量,价值,数量。然后进行分类讨论:

  • s_i=1时,是 0-1背包。
  • s_i=0时,是完全背包。
  • 其他为多重背包。

然后套用以上的状态转移方程即可。

代码
#include <bits/stdc++.h>
using namespace std;
int w[maxn],v[maxn],s[maxn],dp[maxm];
int main(){int n,m;cin>>m>>m;for(int i=1;i<=n;i++)cin>>w[i]>>v[i]>>s[i];for(int i=1;i<=n;i++){if(s[i]==1){//0-1背包 for(int j=m;j>=w[i];j--)dp[j]=max(dp[j],dp[j-w[i]]+v[i]);}else if(s[i]==0){//完全背包 for(int j=w[i];j<=m;j++)dp[j]=max(dp[j],dp[j-w[i]]+v[i]);}else{//多重背包(朴素),转0-1背包 for(int j=m;j>=w[i];j--){for(int k=1;k<s[i] && k*w[i]<=m;k++)dp[j]=max(dp[j],dp[j-k*w[i]]+k*v[i]);} }}cout<<dp[m]<<endl;return 0;
}

分组背包

例题:P1757

思路

和 0-1背包 类似,只用一个二维数组存储每个组的解就行了。每组按 0-1 背包的解法做就ok了。

代码

#include <bits/stdc++.h>
using namespace std;
vector<int> w[maxn],v[maxn];
int dp[maxm];
int main(){for(int i=0;i<maxn;i++){w[i].push_back(0);v[i].push_back(0);}int m,n;cin>>m>>n;int kind=0;//种类数 for(int i=1;i<=n;i++){int a,b,c;//a是重量,b是价值 cin>>a>>b>>c;//c是种类 w[c].push_back(a);v[c].push_back(b);kind=max(kind,c);}for(int i=1;i<=kind;i++){for(int j=m;j>=0;j--){//倒着循环(0-1)背包 for(int k=1;k<(int)w[i].size();k++){if(j>=w[i][k])dp[j]=max(dp[j],dp[j-w[i][k]]+v[i][k]);} }}cout<<dp[m]<<endl;return 0;
}

结尾

这篇 blog 用了我整整 1 天的时间整理,主要因为之前的背包的 blog 太散了,之后还会整理线性 dp 和区间 dp 的blog。看在我写了 7k+ 字的份上,点个赞再走吧。

友情提醒:虽然模板都是正确的,但直接提交会让你喜提 0 分(里面的 maxn 我都没有定义)

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

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

相关文章

【图像匹配】基于Harris算法的图像匹配,matlab实现

博主简介&#xff1a;matlab图像代码项目合作&#xff08;扣扣&#xff1a;3249726188&#xff09; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 本次案例是基于基于Harris算法的图像匹配&#xff0c;用matlab实现。 一、案例背景和算法介绍 …

Observability:日志管理的最佳实践 - 利用日志更快地解决问题

作者&#xff1a;来自 Elastic Luca Wintergerst•David Hope•Bahubali Shetti 在当今快速发展的软件开发环境中&#xff0c;高效的日志管理对于维护系统可靠性和性能至关重要。随着基础架构和应用程序组件的不断扩展和复杂化&#xff0c;运营和开发团队的职责也不断增加且越来…

yolov8区域入侵检测警报系统-pyside6可视化界面

yolov8区域入侵检测警报系统&#xff0c;是微智启软件工作室基于yolov8目标追踪和pyside6开发&#xff0c;在window的pycharm或者vscode里运行&#xff0c;可以应用于多个领域&#xff0c;检测统计物体个数以及入侵语音警报。 功能介绍 可以应用于 江河流域危险区域禁止游泳警…

利用AI技术提升ISP处理:图像质量的四大关键模块

随着智能手机和数码相机的飞速发展&#xff0c;图像质量成为了影响用户体验的关键因素之一。图像信号处理&#xff08;ISP&#xff0c;Image Signal Processing&#xff09;管道是将图像传感器捕捉到的原始数据转化为高质量输出的核心技术。然而&#xff0c;传统的ISP处理方法在…

螺丝、螺母、垫片等紧固件常用类型详细介绍

螺钉、螺母、垫片等紧固件介绍 螺钉 杯头内六角 首先介绍一下杯头内六角&#xff0c;杯头内六角是我们用的最常见的一种螺钉&#xff0c;如果你对选择螺钉没有什么想法&#xff0c;可以直接无脑选杯头内六角去使用。 比如说我们有一个零件加工了通孔&#xff0c;另一个零件加…

vmware,centos8(虚拟机) 的安装

安装vmware 点击下方网址 虚拟机安装地址https://www1.msc23.cn/vm/?bd_vid8829610582362807097选择VMware17 打开文件所在地&#xff0c;双击安装 同意条款 选择安装位置 不将VMware配置到环境变量path 不检查更新,不加入客户体验 创建桌面快捷方式 开始安装 安装完成…

CSP-J/S 考试介绍

CSP-J/S是由中国计算机学会&#xff08;CCF&#xff09;主办的非专业级别的软件能力认证考试。 CSP-J/S全称为CCF CSP-J/S&#xff0c;是CCF计算机软件能力认证&#xff08;简称CCFCSP认证&#xff09;中的一个部分&#xff0c;重点考察软件开发者实际编程能力。该项认证由CCF…

MTC完成右臂抓取放置任务\\放置姿态设置

#include "mtc_tutorial/mtc_glass_bottle.hpp" static const rclcpp::Logger LOGGER rclcpp::get_logger("mtc_glass_right"); // 获取节点基础接口的实现 rclcpp::node_interfaces::NodeBaseInterface::SharedPtr MTCTaskNode_Right::getNodeBaseInterf…

棋盘格角点检测-libcbdetect

libcbdetect libcbdetect 是一个用于自动子像素级别的棋盘格&#xff08;checkerboard&#xff09;、棋盘&#xff08;chessboard&#xff09;以及 Deltille 图案检测的库。它主要由 C 编写&#xff0c;旨在提供高精度、高鲁棒性的角点检测和图案组合功能&#xff0c;是一种基…

使用HTML和CSS制作网页的全面指南

目录 引言 一、理解HTML 1. 什么是HTML&#xff1f; 2. HTML文档的基本结构 3. 常用的HTML标签 4. 示例&#xff1a;创建一个简单的HTML页面 二、理解CSS 1. 什么是CSS&#xff1f; 2. CSS的使用方式 3. CSS选择器和属性 4. 常用的CSS属性 三、创建网页的步骤 1. 规…

【Java数据结构】二叉树

目录 树树的特征树的概念 二叉树两种特殊的二叉树二叉树的性质二叉树的基本操作4 种遍历二叉树的方式判断一棵树是不是完全二叉树获取二叉树总共的节点个数获取叶子节点的个数获取第 k 层的节点个数获取二叉树的高度检测值为 value 的元素是否存在 二叉树基本操作完整代码 树 …

VS code 安装使用配置 Continue

Continue 插件介绍 Continue 是一款高效的 VS Code 插件&#xff0c;提供类似 GitHub Copilot 的功能&#xff0c;旨在提升开发者的编程效率。其配置简单&#xff0c;使用体验流畅&#xff0c;深受开发者喜爱。 主要功能特点 智能代码补全 Continue 能够基于当前代码上下文生…

年化60.7%,最大回撤-16.5%,RSRS标准分择时效果差不多

原创内容第653篇&#xff0c;专注量化投资、个人成长与财富自由。 中秋节&#xff0c;祝大家中秋快乐&#xff01; 人有悲欢离合&#xff0c;月有阴晴圆缺&#xff0c;此事古难全。但愿人长久&#xff0c;千里共婵娟。 今天引入RSRS来择时&#xff0c;看下策略效果。 年化60.7…

Python编码系列—Python代理模式:为对象赋予超能力的魔法

&#x1f31f;&#x1f31f; 欢迎来到我的技术小筑&#xff0c;一个专为技术探索者打造的交流空间。在这里&#xff0c;我们不仅分享代码的智慧&#xff0c;还探讨技术的深度与广度。无论您是资深开发者还是技术新手&#xff0c;这里都有一片属于您的天空。让我们在知识的海洋中…

C++掉血迷宫

目录 开头程序程序的流程图程序游玩的效果下一篇博客要说的东西 开头 大家好&#xff0c;我叫这是我58。 程序 #include <iostream> #include <string> #include <cstring> using namespace std; enum RBYG {R 1,B 2,Y 4,G 7, }; struct heal {int ix…

【例题】lanqiao549 扫雷

输入 3 4 0 1 0 0 1 0 1 0 0 0 1 0输出 2 9 2 1 9 4 9 2 1 3 9 2解题思路 分类讨论&#xff1a; 如果原来的方格整数为1&#xff0c;输出9如果原来的方格整数为0&#xff0c;输出周围8个&#xff08;最多八个&#xff09;的地雷数量和 代码 如何遍历一个方格mp[i][j]周围…

c++中引用是通过指针的方式实现

其实在汇编层面上&#xff0c;引用的代码和指针的代码是一致的。 先看指针情况下的代码分析&#xff0c;如下所示&#xff1a; #include <iostream>using namespace std;void fuzhi(int *x)//引用传参 {*x 10; }int main(int argc, char** argv) {int a 0;int b;a …

架构设计——概念和基础

&#x1f3e0;1 架构基础 想要搞清楚架构到底指什么&#xff0c;架构与框架的区别&#xff0c;就需要了解梳理系统、子系统、模块、组件、框架和架构 1.1系统与子系统 1.1.1系统 wiki:系统泛指由一群有关联的个体组成&#xff0c;根据某种规则运作&#xff0c;能完成个别元…

Python编码系列—Python外观模式:简化复杂系统的快捷方式

&#x1f31f;&#x1f31f; 欢迎来到我的技术小筑&#xff0c;一个专为技术探索者打造的交流空间。在这里&#xff0c;我们不仅分享代码的智慧&#xff0c;还探讨技术的深度与广度。无论您是资深开发者还是技术新手&#xff0c;这里都有一片属于您的天空。让我们在知识的海洋中…

QT安装时出现错误(镜像)

QT下载网站 下载网址 QT安装时出现错误 解决方法 按“win+R”键弹出“运行”窗口,输入"cmd",点击确定; 打开如下图运行框,将Qt文件拖到窗口里->空一格输入“–mirror https://mirrors.aliyun.com/qt”->按enter键进入,即可成功安装 正式安