【C++代码】爬楼梯,不同路径,整数拆分,不同搜索树,动态规划--代码随想录

news2024/11/22 10:11:57
  • 动态规划,英文:Dynamic Programming,简称DP,如果某一问题有很多重叠子问题,使用动态规划是最有效的。所以动态规划中每一个状态一定是由上一个状态推导出来的,这一点就区分于贪心,贪心没有状态推导,而是从局部直接选最优的,例如:有N件物品和一个最多能背重量为W 的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大。动态规划中dp[j]是由dp[j-weight[i]]推导出来的,然后取max(dp[j], dp[j - weight[i]] + value[i])。但如果是贪心呢,每次拿物品选一个最大的或者最小的就完事了,和上一个状态没有关系。

  • 状态转移公式(递推公式)是很重要,但动规不仅仅只有递推公式。对于动态规划问题,我将拆解为如下五步曲,这五步都搞清楚了,才能说把动态规划真的掌握了!

    • 确定 dp 数组(dp table)以及下标的含义
    • 确定递推公式
    • dp 数组如何初始化
    • 确定遍历顺序
    • 举例推导 dp 数组
  • **因为一些情况是递推公式决定了dp数组要如何初始化!**写动规题目,代码出问题很正常!找问题的最好方式就是把dp数组打印出来,看看究竟是不是按照自己思路推导的!一些同学对于dp的学习是黑盒的状态,就是不清楚dp数组的含义,不懂为什么这么初始化,递推公式背下来了,遍历顺序靠习惯就是这么写的,然后一鼓作气写出代码,如果代码能通过万事大吉,通过不了的话就凭感觉改一改。

题目:斐波那契数

  • 斐波那契数 (通常用 F(n) 表示)形成的序列称为 斐波那契数列 。该数列由 01 开始,后面的每一项数字都是前面两项数字的和。也就是:F(0) = 0,F(1) = 1; F(n) = F(n - 1) + F(n - 2),其中 n > 1

  • class Solution {
    public:
        int fib(int n) {
            if(n<2){
                return n;
            }
            int res=fib(n-1)+fib(n-2);
            return res;
        }
    };
    
  • 时间复杂度:O(2^n);空间复杂度:O(n),算上了编程语言中实现递归的系统栈所占空间

  • 动态规划:这里我们要用一个一维 dp 数组来保存递归的结果;确定dp数组以及下标的含义,dp[i]的定义为:第i个数的斐波那契数值是dp[i]

    • 确定递推公式:状态转移方程 dp[i] = dp[i - 1] + dp[i - 2];
    • dp数组如何初始化:dp[0] = 0; dp[1] = 1;
    • 确定遍历顺序:从递归公式dp[i] = dp[i - 1] + dp[i - 2];中可以看出,dp[i]是依赖 dp[i - 1] 和 dp[i - 2],那么遍历的顺序一定是从前到后遍历的
    • 举例推导dp数组
  • class Solution {
    public:
        int fib(int n) {
            if(n<2){
                return n;
            }
            vector<int> dp(n+1,0);
            dp[1]=1;
            for(int i=2;i<dp.size();i++){
                dp[i]=dp[i-1]+dp[i-2];
            }
            return dp[dp.size()-1];
        }
    };
    
  • 时间复杂度:O(n); 空间复杂度:O(n)

  •         if(n<2){
                return n;
            }
            int dp[2]={0,1};
            for(int i=2;i<n+1;i++){
                dp[i%2]=dp[0]+dp[1];
            }
            return dp[(n)%2];
    
  • 时间复杂度:O(n);空间复杂度:O(1)

题目:爬楼梯

  • 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。每次你可以爬 12 个台阶。你有多少种不同的方法可以爬到楼顶呢?

  • 爬到第一层楼梯有一种方法,爬到二层楼梯有两种方法。那么第一层楼梯再跨两步就到第三层 ,第二层楼梯再跨一步就到第三层。所以到第三层楼梯的状态可以由第二层楼梯 和 到第一层楼梯状态推导出来,那么就可以想到动态规划了此时大家应该发现了,这不就是斐波那契数列么!

  • class Solution {
    public:
        int climbStairs(int n) {
            if(n<3){
                return n;
            }
            int dp[2]={1,2};
            for(int i=2;i<n;i++){
                dp[i%2]=dp[0]+dp[1];
            }
            return dp[(n-1)%2];
        }
    };
    
  • 后面将讲解的很多动规的题目其实都是当前状态依赖前两个,或者前三个状态,都可以做空间上的优化,但我个人认为面试中能写出版本一就够了哈,清晰明了,如果面试官要求进一步优化空间的话,我们再去优化

题目:使用最小花费爬楼梯

  • 给你一个整数数组 cost ,其中 cost[i] 是从楼梯第 i 个台阶向上爬需要支付的费用。一旦你支付此费用,即可选择向上爬一个或者两个台阶。你可以选择从下标为 0 或下标为 1 的台阶开始爬楼梯。请你计算并返回达到楼梯顶部的最低花费。

    • 确定dp数组以及下标的含义:本题只需要一个一维数组dp[i]就可以了。dp[i]的定义:到达第i台阶所花费的最少体力为dp[i]
    • 确定递推公式:可以有两个途径得到dp[i],一个是dp[i-1] 一个是dp[i-2]。dp[i - 1] 跳到 dp[i] 需要花费 dp[i - 1] + cost[i - 1]。dp[i - 2] 跳到 dp[i] 需要花费 dp[i - 2] + cost[i - 2]。一定是选最小的,所以dp[i] = min(dp[i - 1] + cost[i - 1], dp[i - 2] + cost[i - 2]);
    • dp数组如何初始化:看一下递归公式,dp[i]由dp[i - 1],dp[i - 2]推出,既然初始化所有的dp[i]是不可能的,那么只初始化dp[0]和dp[1]就够了,其他的最终都是dp[0]dp[1]推出。题目描述中明确说了 “你可以选择从下标为 0 或下标为 1 的台阶开始爬楼梯。” 也就是说 到达 第 0 个台阶是不花费的,但从 第0 个台阶 往上跳的话,需要花费 cost[0]。所以初始化 dp[0] = 0,dp[1] = 0;
  • class Solution {
    public:
        int minCostClimbingStairs(vector<int>& cost) {
            if(cost.size()<3){
                return min(cost[0],cost[1]);
            }
            vector<int> dp(cost.size()+1,0);
            for(int i=2;i<dp.size();i++){
                dp[i]=min(dp[i-1]+cost[i-1],dp[i-2]+cost[i-2]);
            }
            return dp[cost.size()];
        }
    };
    

题目:不同路径

  • 一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。问总共有多少条不同的路径?

  • 这道题目,刚一看最直观的想法就是用图论里的深搜,来枚举出来有多少种路径。注意题目中说机器人每次只能向下或者向右移动一步,那么其实机器人走过的路径可以抽象为一棵二叉树,而叶子节点就是终点!

  • class Solution {
    public:
        int track(int i,int j,int m,int n){
            if(i>m||j>n){
                return 0;
            }
            if(i==m && j==n){
                return 1;
            }
            return track(i+1,j,m,n)+track(i,j+1,m,n);
        }
        int uniquePaths(int m, int n) {
            return track(0,0,m-1,n-1);
        }
    };//超时
    
  • 那二叉树的节点个数就是 2^(m + n - 1) - 1。可以理解深搜的算法就是遍历了整个满二叉树(其实没有遍历整个满二叉树,只是近似而已);深搜代码的时间复杂度为O(2^(m + n - 1) - 1),可以看出,这是指数级别的时间复杂度,是非常大的。

  • 动态规划:机器人从(0 , 0) 位置出发,到(m - 1, n - 1)终点。

    • 确定dp数组(dp table)以及下标的含义:dp[i][j] :表示从(0 ,0)出发,到(i, j) 有dp[i][j]条不同的路径。
    • 确定递推公式:想要求dp[i ][ j],只能有两个方向来推导出来,即dp[i - 1] [j] 和 dp[i] [j - 1]。那么很自然,dp[i][j] = dp[i - 1] [j] + dp[i] [j - 1],因为dp[i][j]只有这两个方向过来。
    • dp数组的初始化:首先dp[i] [0]一定都是1,因为从(0, 0)的位置到(i, 0)的路径只有一条,那么dp[0] [j]也同理。
    • 确定遍历顺序:dp[i] [j]都是从其上方和左方推导而来,那么从左到右一层一层遍历就可以了。
  • class Solution {
    public:
        int uniquePaths(int m, int n) {
            vector<vector<int>> dp(m,vector<int>(n,1));
            for(int i=1;i<m;i++){
                for(int j=1;j<n;j++){
                    dp[i][j]=dp[i-1][j]+dp[i][j-1];
                }
            }
            return dp[m-1][n-1];
        }
    };
    
  • 时间复杂度:O(m × n);空间复杂度:O(m × n)

  • 一共m,n的话,无论怎么走,走到终点都需要 m + n - 2 步。在这m + n - 2 步中,一定有 m - 1 步是要向下走的,不用管什么时候向下走。可以转化为,给你m + n - 2个不同的数,随便取m - 1个数,有几种取法。那么这就是一个组合问题了。求组合的时候,要防止两个int相乘溢出! 所以不能把算式的分子,分母都算出来再做除法。需要在计算分子的时候,不断除以分母,代码如下:

    • class Solution {
      public:
          int uniquePaths(int m, int n) {
              long long son=1;
              int mom=m-1;
              int count=m-1;
              int t=m+n-2;
              while(count--){
                  son *= t--;
                  while(mom!=0 && son%mom==0){
                      son /= mom; 
                      mom--;
                  }
              }
              return son;
          }
      };
      

题目:不同路径 II

  • 一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish”)。现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?网格中的障碍物和空位置分别用 10 来表示。

  • 数论解决,完全不行,不止一块障碍物

    • class Solution {
      public:
          int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
              int flag =0;
              int temp_m=0,temp_n=0;
              for(int i=0;i<obstacleGrid.size();i++){
                  for(int j=0;j<obstacleGrid[0].size();j++){
                      if(obstacleGrid[i][j]){
                          temp_m=i;
                          temp_n=j;
                          flag=1;
                          break;
                      }
                  }
              }
              int count_sum=obstacleGrid.size()-1;
              long long son_sum=1;
              int mom_sum=obstacleGrid.size()-1;
              int mn=obstacleGrid.size()+obstacleGrid[0].size()-2;
              while(count_sum--){
                  son_sum *= mn--;
                  while(mom_sum!=0 && son_sum%mom_sum==0){
                      son_sum /= mom_sum;
                      mom_sum--;
                  }
              }
              if(flag==0){
                  return son_sum;
              }
              long long son1=1;
              int mom1 = temp_m;
              int count =temp_m;
              int mn1 = temp_m+temp_n;
              while(count--){
                  son1 *= mn1--;
                  while(mom1!=0 && son1%mom1==0){
                      son1 /= mom1;
                      mom1--;
                  }
              }
              long long son2=1;
              int mom2 = obstacleGrid.size()-temp_m-1;
              int count2 = obstacleGrid.size()-temp_m-1;
              int mn2 = obstacleGrid.size()-temp_m+obstacleGrid[0].size()-temp_n-2;
              while(count2--){
                  son2 *= mn2--;
                  while(mom2!=0 && son2%mom2==0){
                      son2 /= mom2;
                      mom2--;
                  }
              }
              return son_sum-son1*son2;
          }
      };//
      
  • 动态规划:确定dp数组(dp table)以及下标的含义,dp[i][j] :表示从(0 ,0)出发,到(i, j) 有dp[i][j]条不同的路径。

  • 确定递推公式:dp[i][j] = dp[i - 1] [j] + dp[i] [j - 1]。因为有了障碍,(i, j)如果就是障碍的话应该就保持初始状态(初始状态为0)。

  • dp数组如何初始化:从(0, 0)的位置到(i, 0)的路径只有一条,所以dp[i] [0]一定为1,dp[0] [j]也同理。但如果(i, 0) 这条边有了障碍之后,障碍之后(包括障碍)都是走不到的位置了,所以障碍之后的dp[i] [ 0]应该还是初始值0。

  • class Solution {
    public:
        int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
           int m=obstacleGrid.size();
           int n=obstacleGrid[0].size();
           if(obstacleGrid[m-1][n-1]==1 || obstacleGrid[0][0]==1){
               return 0;
           }
           vector<vector<int>> dp(m,vector<int>(n,0));
           for(int i=0;i<m&&obstacleGrid[i][0]==0;i++){
               dp[i][0]=1;
           }
           for(int i=0;i<n&&obstacleGrid[0][i]==0;i++){
               dp[0][i]=1;
           }
           for(int i=1;i<m;i++){
               for(int j=1;j<n;j++){
                   if(obstacleGrid[i][j]==1){
                       continue;
                   }
                   dp[i][j]=dp[i-1][j]+dp[i][j-1];
               }
           }
           return dp[m-1][n-1];
        }
    };
    
  • 时间复杂度:O(n × m),n、m 分别为obstacleGrid 长度和宽度;空间复杂度:O(n × m)

题目:整数拆分

  • 给定一个正整数 n ,将其拆分为 k正整数 的和( k >= 2 ),并使这些整数的乘积最大化。返回 你可以获得的最大乘积

  • 确定dp数组(dp table)以及下标的含义:dp[i]:分拆数字 i,可以得到的最大乘积为dp[i]。dp[i]的定义将贯彻整个解题过程,下面哪一步想不懂了,就想想dp[i]究竟表示的是啥!

  • 确定递推公式:其实可以从1遍历j,然后有两种渠道得到dp[i].一个是j * (i - j) 直接相乘。一个是j * dp[i - j],相当于是拆分(i - j),对这个拆分不理解的话,可以回想dp数组的定义。j是从1开始遍历,拆分j的情况,在遍历j的过程中其实都计算过了。那么从1遍历j,比较(i - j) * j和dp[i - j] * j 取最大的。递推公式:dp[i] = max(dp[i], max((i - j) * j, dp[i - j] * j));也可以这么理解,j * (i - j) 是单纯的把整数拆分为两个数相乘,而j * dp[i - j]是拆分成两个以及两个以上的个数相乘。所以递推公式:dp[i] = max({dp[i], (i - j) * j, dp[i - j] * j});

  • dp的初始化:这里我只初始化dp[2] = 1,从dp[i]的定义来说,拆分数字2,得到的最大乘积是1

  • class Solution {
    public:
        int integerBreak(int n) {
            vector<int> dp(n+1);
            dp[2]=1;
            for(int i=3;i<=n;i++){
                for(int j=1;j<=i/2;j++){
                    dp[i]=max(dp[i],max((i-j)*j,dp[i-j]*j));
                }
            }
            return dp[n];
        }
    };
    
  • 时间复杂度:O(n^2); 空间复杂度:O(n)

题目:不同的二叉搜索树

  • 给你一个整数 n ,求恰由 n 个节点组成且节点值从 1n 互不相同的 二叉搜索树 有多少种?返回满足题意的二叉搜索树的种数。

  • n为1的时候有一棵树,n为2有两棵树,来看看n为3的时候

  • 在这里插入图片描述

    • 元素1为头结点搜索树的数量 = 右子树有2个元素的搜索树数量 * 左子树有0个元素的搜索树数量
    • 元素2为头结点搜索树的数量 = 右子树有1个元素的搜索树数量 * 左子树有1个元素的搜索树数量
    • 元素3为头结点搜索树的数量 = 右子树有0个元素的搜索树数量 * 左子树有2个元素的搜索树数量
  • 确定dp数组(dp table)以及下标的含义:dp[i] : 1到i为节点组成的二叉搜索树的个数为dp[i]。也可以理解是i个不同元素节点组成的二叉搜索树的个数为dp[i] ,都是一样的。

  • 确定递推公式:dp[i] += dp[以j为头结点左子树节点数量] * dp[以j为头结点右子树节点数量];j相当于是头结点的元素,从1遍历到i为止。所以递推公式:dp[i] += dp[j - 1] * dp[i - j]; ,j-1 为j为头结点左子树节点数量,i-j 为以j为头结点右子树节点数量

  • dp数组如何初始化:从定义上来讲,空节点也是一棵二叉树,也是一棵二叉搜索树,这是可以说得通的。从递归公式上来讲,dp[以j为头结点左子树节点数量] * dp[以j为头结点右子树节点数量] 中以j为头结点左子树节点数量为0,也需要dp[以j为头结点左子树节点数量] = 1, 否则乘法的结果就都变成0了。

  • class Solution {
    public:
        int numTrees(int n) {
            vector<int> dp(n+1);
            dp[0]=1;
            for(int i=1;i<=n;i++){
                for(int j=1;j<=i;j++){
                    dp[i] += dp[j-1]*dp[i-j];
                }
            }
            return dp[n];
        }
    };
    
  • 时间复杂度: O ( n 2 ) O(n^2) O(n2);空间复杂度: O ( n ) O(n) O(n)

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

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

相关文章

YOLOv7-QAT量化部署

目录 前言一、QAT量化浅析二、YOLOv7模型训练1. 项目的克隆和必要的环境依赖1.1 项目的克隆1.2 项目代码结构整体介绍1.3 环境安装 2. 数据集和预训练权重的准备2.1 数据集2.2 预训练权重准备 3. 训练模型3.1 修改模型配置文件3.2 修改数据配置文件3.3 训练模型3.4 mAP测试 三、…

NetSuite数据备份办法

本周有同学问有啥办法可以实现NetSuite的数据备份&#xff1f;这是个常见问题&#xff0c;今天总结一下。 我们认为可以选择的技术路线有下面几个&#xff1a; 从技术可行性、数据可利用角度&#xff0c;毫无疑问我们将推荐第三种办法。所以&#xff0c;今朝就介绍一下。 Ana…

UE5使用Dash插件实现程序化地形场景制作

目录 0 dash下载后激活 1 初步使用 2 导入bridge的资产路径 3 练习成果 4 参考链接 0 dash下载后激活 1 初步使用 Dash插件点击蓝色的A&#xff0c;可以使用。 通过输入不同提示命令&#xff0c;来激活不同的功能。 2 导入bridge的资产路径 这里需要注意是UAsserts…

解决找不到vcruntime140.dll,无法继续执行代码方法

在计算机使用过程中&#xff0c;我们经常会遇到一些错误提示&#xff0c;其中之一就是“找不到vcruntime140.dll”。这个错误通常发生在运行某些程序或游戏时&#xff0c;它会导致程序无法正常启动或运行。那么&#xff0c;找不到vcruntime140.dll&#xff0c;无法继续执行代码…

【大数据Hive】hive 表数据优化使用详解

目录 一、前言 二、hive 常用数据存储格式 2.1 文件格式-TextFile 2.1.1 操作演示 2.2 文件格式 - SequenceFile 2.2.1 操作演示 2.3 文件格式 -Parquet 2.3.1 Parquet简介 2.3.2 操作演示 2.4 文件格式-ORC 2.4.1 ORC介绍 2.4.2 操作演示 三、hive 存储数据压缩优…

椭圆曲线的参数(二)

一、椭圆曲线的参数 1.1 背景 假设一条椭圆曲线方程为 y^2 =x^3+ax+b确定这条椭圆曲线方程参数是p,a,b,G,n,h,除了参数a,b ,其他参数的意义 p为质数,(mod p)运算G为基点n为点G的阶h是椭圆曲线上所有点的个数m与n相除的商的整数部分1.2 方程(y^2 =x^3+x+6,P=11) 椭圆曲线…

基于springboot,vue校园社团管理系统

开发工具&#xff1a;IDEA 服务器&#xff1a;Tomcat9.0&#xff0c; jdk1.8 项目构建&#xff1a;maven 数据库&#xff1a;mysql5.7 系统分前后台&#xff0c;项目采用前后端分离 前端技术&#xff1a;vueelementUI 服务端技术&#xff1a;springbootmybatis-plus 本系…

信息系统项目管理师教程 第四版【第6章-项目管理概论-思维导图】

信息系统项目管理师教程 第四版【第6章-项目管理概论-思维导图】 课本里章节里所有蓝色字体的思维导图

Linux 网络驱动实验(PHY芯片LAN8720)

目录 嵌入式网络简介嵌入式下的网络硬件接口 网络驱动是linux 里面驱动三巨头之一&#xff0c;linux 下的网络功能非常强大&#xff0c;嵌入式linux 中也常 常用到网络功能。前面我们已经讲过了字符设备驱动和块设备驱动&#xff0c;本章我们就来学习一下 linux 里面的网络设备…

【音视频|PCM】PCM格式详解

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; &#x1f923;本文内容&#x1f923;&a…

【队列的顺序表示,链式表示】

文章目录 队列的表示和实现相关术语队列的表示链队的表示链队的定义链队的初始化销毁链队列 链队列的入队出栈 队列的表示和实现 相关术语 队列&#xff08;Queue&#xff09;是仅在表尾进行插入操作&#xff0c;在表头进行删除操作的线性表。表尾即an端&#xff0c;称为队尾…

分布式锁其实很简单,6行代码教你实现redis分布式锁

一、前言 分布式锁是一种用于协调分布式系统中多个节点之间对共享资源进行访问控制的机制。它可以确保在分布式环境下&#xff0c;同一时间只有一个节点能够获取到锁&#xff0c;并且其他节点需要等待释放锁后才能获取。 以下是使用分布式锁的几个常见场景和原因&#xff1a;…

ChatGPT 驱动软件开发:AI 在软件研发全流程中的革新与实践

目录 内容简介作者简介专家推荐读者对象目录直播预告 计算机技术的发展和互联网的普及&#xff0c;使信息处理和传输变得更加高效&#xff0c;极大地改变了金融、商业、教育、娱乐等领域的运作方式。数据分析、人工智能和云计算等新兴技术&#xff0c;也在不断地影响和改变着各…

misc学习(4)Traffic(流量分析)-

感悟&#xff1a;回想起自己学的计算机网络和网络协议分析&#xff0c;有所感悟&#xff1a;计算机网络好比将一群人区分开来&#xff08;局域网&#xff09;&#xff0c;为了能够使得不同部分的人能够沟通&#xff08;wireshark中的数据包&#xff09;&#xff0c;就设置了网络…

高级深入--day43

通过Fiddler进行手机抓包 通过Fiddler抓包工具&#xff0c;可以抓取手机的网络通信&#xff0c;但前提是手机和电脑处于同一局域网内&#xff08;WI-FI或热点&#xff09;&#xff0c;然后进行以下设置&#xff1a; 用Fiddler对Android应用进行抓包 打开Fiddler设置 在Conne…

DIANA算法c++实现

第一步对具有最大直径的簇中每个点计算平均相异度找出最大的点放入splinter group&#xff0c;其余放在放入splinter group 第二步 在old party里找出到splinter group中点的最近距离 < 到old party中点的最近距离的点&#xff0c;并将该点加入splinter group 重复第二步的…

共用体开发案例

有若干个人员的数据,其中有学生和教师。学生的数据中包括:姓名、号码性别、职业、班级。教师的数据包括:姓名、号码、性别、职业、职务。要求用同一个表格来处理。 #include <stdio.h>struct Person {char name[32];int age;char zhiYe;char addr[32];union {int class;…

Ubuntu系统编译调试QGIS源码保姆级教程

在之前的文章中&#xff0c;我详细介绍了怎么在Windows下编译QGIS源码&#xff0c;也得到了不错的反馈。但是不足的是Windows下只能编译QGIS的Release模式和RelWithDebInfo模式&#xff0c;想要分析源码&#xff0c;“断点调试”肯定是少不了的&#xff0c;但是这两种模式虽然也…

论文写作框架示例:论软件系统建模方法及其应用

标题 前言题目要求写作框架(1)摘要(300~330字)(2)正文(2000~2500字,2200字左右为宜)(3)收尾(200字左右)前言 本章内容参考了51cto的薛老师的《软考论文高分特训与范文10篇》的内容,是帮助初学者打开写作思路的工具,而不是必须要遵循的模式。建议软考人多读多看…

集丰照明|灯光布局没做好,几百万装修也拯救不了

俗话说拍照要看灯光的位置&#xff0c;我们在装修的时候也要注重灯光的摆放&#xff0c;不然可能你花了很多钱的装修&#xff0c;结果就会因为灯光的布局不合理&#xff0c;导致效果大打折扣。 装修也是一样&#xff0c;忽略掉灯光&#xff0c;可能就会发生花了几十万&#xff…