Excel求解运输问题——以福斯特公司问题为例

目录 1.1 问题 福斯特问题例 1.2 数学模型 1.3 excel求解 第一步:建立一个工作表 第二步:求解器求解 1.1 问题 运输问题通常出现在计划货物配送机从供给地区到达需求地区之间的服务中,一般供给地区货物数量有限,需求地区货物需求量已知。常见目标是使货物从起点到终点的运输成本最低。 福斯特问题例: 福斯特发电机公司面临一个运输问题,从3个加工厂运输一种产品到4个分销中心。3个加工厂在后3个月的计划期内的生产能力如下表所示: 起点加工厂3个月的生产能力(单位)1克利夫兰50002贝德福德60003约克2500总计:13500 公司通过波士顿、芝加哥、圣路易斯和莱克星顿的4个分销中心来分销这种发电机,每个分销中心的后3个月的需求预测如下: 终点分销中心3个月的需求预测(单位)1波士顿60002芝加哥40003圣路易斯20004莱克星顿1500总计:13500 各加工厂到分销中心的单位运输成本如下图所示: 起点终点波士顿芝加哥圣路易斯莱克星顿克利夫兰3276贝德福德7523约克2545 管理层想知道各个加工厂运输到分销中心的产品运输量应该是多少。我们可以用线性规划模型解决这类运输问题,用双下标决策变量来描述,表示从加工厂1克利夫兰到分销中心1波士顿的运输量,表示从加工厂1克利夫兰到分销中心2芝加哥的运输量,以此类推。一般情况下,m个起点和n个重点的运输问题的决策变量常被表示成以下形式: -------从起点i到终点j的运输量。i=1,2,3,...,m; j=1,2,3...,n 1.2 数学模型 根据生产能力约束和目标函数建立线性规划模型,如下所示: 注意,最后一条决策变量的取值范围记得加上。 1.3 excel求解 接下来介绍怎么使用excel求解简单的运输问题。 第一步:建立一个工作表 首先输入运输成本、起终点供给量及终点节点的需求量。然后在工作表底端构建这个问题的线性规划问题。所有的线性规划问题都包含四个要素:决策变量、目标函数、左端约束条件和右端值。 在单元格C13中输入公式=SUMPRODUCT(B5:E7,B17:F19),用来计算解的总运输成本。单元格F17=SUM(B17:E17),F18、F19类推,计算各个起点运往各个分销商的供给总量。单元格B20=SUM(B17:B19),C20到E20类推,计算的是运入各个分销商的货物量。 第二步:求解器求解 选择数据>规划求解器,设置规划求解参数,如下图所示: 点击求解,结果如下所示: 目标函数最小值为39500,决策变量=3500,,,,,,其他决策变量都为0,即对应的路线上没有运输量。

Impala vs. Presto简要对比梳理

文章目录 旧日报(Impala)核心语法时间范围时间转换JSON解析 新日报(Presto)核心语法时间范围时间转换JSON解析 其他参考 腾讯灯塔产品相关介绍文档: 腾讯灯塔产品文档DataTalk:开放的通用BI可视化平台腾讯灯塔DataTalk——如同乐高,这是一个开放/自由的数据可视化世界 SQL模式下的第一个tab【查询结果】右边的帮助提示信息如下: ① 请确保在SQL查询语句末尾带上limit条件,否则页面默认显示前5000条结果; ② Impala SQL语法指南 (查询托管在灯塔集群的数据需使用) ③ OneSQL 语法指南 (跨源查询模式需使用) 腾讯灯塔 DataTalk 没有固定的语法,是按查询的数据源SQL语法。 旧日报(Impala) 旧的 DataTalk 页面是引用的灯塔融合引擎(DataInsight的数据源),对应 Impala SQL 语法。 Data TypesImpala SQL Language ReferenceImpala Built-In Functions 核心语法 主要用到 IF、CASE、IN、BETWEEN、CAST、AVG、COUNT 等关键字。 SQL Operators: Arithmetic OperatorsBETWEEN OperatorComparison Operators:=, !=, <>;<, <=, >, >=。EXISTS OperatorILIKE OperatorIN OperatorIREGEXP OperatorIS DISTINCT FROM OperatorIS NULL OperatorIS TRUE OperatorLIKE OperatorLogical Operators:AND、OR、NOTREGEXP OperatorRLIKE Operator Impala Conditional Functions: CASECASE2COALESCEDECODEIFIFNULLISFALSEISNOTFALSEISNOTTRUEISNULLISTRUENONNULLVALUE:等效于 IS NOT NULL。NULLIFNULLIFZERONULLVALUE:等效于 IS NULL。NVLNVL2ZEROIFNULL 时间范围 recent_7_days 是DataTalk中拖入的时间范围交互组件定义的变量。

Linux服务器上配置Anaconda

Linux服务器上配置Anaconda 文章目录 Linux服务器上配置Anaconda前言准备安装可能出现问题1.提示找不到conda指令 总结 前言 本为介绍了在实验室服务器(Linux环境)上配置Anaconda的步骤以及可能遇到的问题。 准备 首先需要在官网上查找自己需要的版本,地址链接在下面: https://repo.anaconda.com/archive/ 后面根据需要加上需要下载的conda版本,通过如下指令下载: wget https://repo.anaconda.com/archive/Anaconda3-2022.10-Linux-x86_64.sh 安装 在root权限下需要首先对下载的安装包先赋权再执行安装程序,输入下面两句命令: > chmod +x Anaconda3-2022.10-Linux-x86_64.sh > ./Anaconda3-2022.10-Linux-x86_64.sh 点击Enter(回车键),终端的下方会出现more一直回车,直到能提示需要输入yes/no,输入yes+继续回车+yes+回车,安装完成! 可能出现问题 1.提示找不到conda指令 最后一步选择了默认的no,然后在终端中输入conda,提示command not found,把它加到系统环境中解决方案是: #将anaconda的bin目录加入PATH,根据版本不同,也可能是~/anaconda3/bin echo 'export PATH="~/anaconda2/bin:$PATH"' >> ~/.bashrc #更新bashrc以立即生效 source ~/.bashrc 运行就可以发现conda可以正常运行,通过conda -V来查看当前版本号: 总结 以上就是Linux服务器上安装Anaconda的步骤和可能出现的部分问题!

BGP在数据中心的应用5——BGP生命周期管理

注: 本文根据《BGP in the Datacenter》整理,有兴趣和英文阅读能力的朋友可以直接看原文:https://www.oreilly.com/library/view/bgp-in-the/9781491983416/上一部分笔记请参考:https://blog.csdn.net/tushanpeipei/article/details/128535543?spm=1001.2014.3001.5501 一、常用的show命令 前面四部分笔记着重于描述现代化数据中心的架构,以及BGP如何应用于数据中心中。在本篇的笔记中主要涉及到的是BGP的维护和排错的相关操作。首先是常用的show命令(不同厂商的设备会有一定的差别): 1.查看BGP的会话信息: 使用命令show bgp summary,结果如图1所示。默认显示的是IPv4的会话信息,如果想要查看IPv6的,乃至其他的会话信息,可以通告AFI/SAFI模型对命令进行修改,例如:show bgp ipv6 unicast summary则是查看IPv6的单播会话信息。 图1: BGP会话输出信息 以下是此输出中需要注意的要点: 列出了此设备所有的邻居(与OSPF等其他协议不同)。列出了每个会话的状态。如果会话处于Established状态,则显示从对等体接收到的路由数量。显示每个会话的正常运行时间(如果会话处于关闭状态,则显示其关闭持续的时间)。显示了节点的路由器ID和ASN等信息。 此外,我们还需要注意的是,这里的neighbor显示的是对等体的hostname,这是BGP中的一个新的能力(capability)“hostname”。它可以在Open报文交互的时候携带上。一旦双方都支持该能力,后续所有的show命令都可以携带上对应的hostname而不是对端的IP,这样能够更加方便我们进行排错。例如:使用命令show ip bgp neighbors neighbor_name可以查看邻居的详细会话信息。详细的会话信息中包括对等体之间协商的能力信息,各个定时器,每一个地址簇的邻居,收发报文等。 2.查看对等体之间的路由交换信息 另外一条常用的命令则是show ip bgp或者show bgp ipv4 unicast。具体的输出信息如图2所示: 图2: BGP路由输出信息 关键字段是路由网段Network、可能的Nexthops以及与每条路由关联的AS_PATH。此屏幕仅显示12个路由中的8个,因为其他两个不被接受。拒绝路由的常见原因是策略决策或检测到AS_PATH环路。此外,每一行开头的星号(*)表示路线有效,即Nexthop是可以到达的。之后,相等符号(=)表示该路由具有多个可用的等成本路径。 此外,如果我们想要查看其中详细的路由信息,则可以使用show ip bgp x.x.x.x(路由网段)进行查看。例如,在这里我们查看10.254.0.3这条路由的详细信息,最终的输出如图3所示: 图3: BGP详细路由输出信息 使用此命令,我们可以仔细检查一条具体的路由。图3显示了该路由包含了哪些属性,以及该设备向哪些对等体通告了该路由。 二、连接外部网络 目前,我们还没有探讨Clos网络与外部网络通信的注意事项。如图4所示,它展示了一个简单的Clos网络通过Exit Leaf访问外网的拓扑: 图4: 连接外部网络拓扑设计 简单来说,Exit01和Exit02是从划分数据中心内部和外部的两个节点,也被称为Border交换机。它们通过连接到Internet节点实现与外部网络的互访以及将Clos网络与外部网络进行隔离。为了保证上述2个目的,我们需要在Border交换机与Internet节点交换路由时,上实现如下2个功能: 使用命令neighbor neighbor_name remove-private-AS all剥离数据中心路由的私网AS号;使用命令aggregate-address summary-route summary-only聚合数据中心路由,并不发送明细路由。当然,一旦路由被聚合,AS_Path信息也会被默认地清除掉。 三、节点维护调度 如果我们需要对数据中网络中的某些节点进行升级,就需要避免路由被发送到正在升级的设备而导致流量损失。例如,在图4中,如果Spine01要升级,我们应该要求所有Leaf节点在最佳路径计算中忽略Spine01,并在此期间将所有流量发送到Spine02,以确保平稳的交通流。同样,对于服务器上连2个Leaf的情况,Spine也需要避免向其中正在升级的Leaf发送流量。 此外,现代数据中心有两个以上的Spine节点。其中四个Spine节点更为常见,在这种情况下,当一个Spine停止使用进行维护时,网络可以保持75%的容量。在传统的企业网络工作设计中,只有两个Spine节点,当单个Spine停止服务时,这将导致更严重的容量损失。相较之下,一些超大型网络中部署了16或32个Spine同时运行,在这种情况下,一个Spine等故障的只会导致容量下降1/16或1/32。 那么,我们如何让流量绕过升级中的节点呢?一个很直接有效的方式就是通过路由策略,在升级前增加去往升级节点路由的AS长度。在BGP的选路规则中,AS_path越短的情况下,越优先。所以流量就可以提前避过这个升级节点。例如,Leaf01访问Leaf04可以通过Spine01或者Spine02(ECMP)。但是现在Spine02需要进行升级。所以我们需要提前在Spine02节点上配置如下路由策略,以增加发送给Leaf节点路由的AS_Path长度: route-map SCHED_MAINT permit 10 set as-path prepend 65000 65000 neighbor ISL route-map SCHED_MAINT out 当下行Leaf节点收到Spine02的路由条目后,由于AS_path长度比从Spine01学习到的更长,所以流量都被切换到Spine01上。如图5所示:

Java理解多线程

Java理解多线程 程序program 是为了完成特定的任务、用某种语言编写的一组指令的集合 简单的说就是我们编写的代码 进程: 进程管理是操作系统重点、难点问题,也是贯穿Linux学习的知识点。那么什么是进程? 1.为什么引入进程的概念? 从理论角度看,是对正在运行的程序过程的抽象; 从实现角度看,是一种数据结构,目的在于清晰地刻画动态系统的内在规律,有效管理和调度进入计算机系统主存储器运行的程序。 2.什么是进程? 狭义定义:进程就是一段程序的执行过程。 广义定义:进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。它是操作系统动态执行的基本单元,在传统的操作系统中,进程既是基本的分配单元,也是基本的执行单元。 进程就是运行的程序,例如我们使用的QQ,就启动了一个进程,操作系统就会进程分配内存空间。——运行的程序 进程是程序的一次执行过程、或是正在运行的一个程序。是动态的过程:有它自身产生、存在、消亡的过程。 关闭了就会释放进程所占的空间!——操作系统的理论知识 线程 线程是进程创建的,是进程的一个实体。 一个进程可以有多个线程。 单线程 多线程 并发:同一个时刻,多个任务交替执行(单核) 并行:同一个时刻,多个任务同时执行(多核) 线程的创建方式1:继承Thread 构造方法 Thread() 分配新的Thread对象 Thread(String name) 分配新的Thread对象 Thread(Runnable target) 分配新的Thread对象 Thread(Runnable target,String name) 分配新的Thread对象 普通方法 static Thread currentThread( ) 返回对当前正在执行的线程对象的引用 long getId() 返回该线程的标识 String getName() 返回该线程的名称 void run() 如果该线程是使用独立的 Runnable 运行对象构造的,则调用该 Runnable 对象的 run 方法 static void sleep(long millions) 在指定的毫秒数内让当前正在执行的线程休眠(暂停执行) void start() 使该线程开始执行:Java虚拟机调用该线程的run() 子线程 //继承 Thread 类 该类就能当做线程使用 /** * * @author Administrator * 写自己的业务代码 */ class Cat extends Thread{ int times = 0; @Override public void run() { //重写run方法 自己的业务逻辑 while(true) { System.

BGP在数据中心的应用4——BGP配置再优化

注: 本文根据《BGP in the Datacenter》整理,有兴趣和英文阅读能力的朋友可以直接看原文:https://www.oreilly.com/library/view/bgp-in-the/9781491983416/上一部分笔记请参考:https://blog.csdn.net/tushanpeipei/article/details/128531548 前要提示: 本篇内容与上一部分笔记连接紧密,在阅读本篇内容时请务必看已经阅读完了上一篇。在这里,我们依然使用的是下图中所显示的网络拓扑来结合阐述BGP配置的优化方案: 图1:演示Clos网络架构 一、接口IP和远端ASN在数据中心中的必要性 在上一章的笔记中,我们已经通过重分发+路由策略代替network,以接口名代替对等体IP的形式,极大的减少了BGP配置中的IP地址出现次数。但是,在BGP配置中依然有存在大量的远端ASN。并且,在BGP配置以外,每条链路的接口依需要配置IP地址。 首先我们来探讨一下这两个部分是否可以进行优化。首先,接口IP地址的配置目的是保证直连的两个节点之间能过TCP/IP协议栈通信。BGP的承载协议为TCP,只有双方的TCP能够通信,BGP的邻居关系才能建立起来。从这个角度来说,IP地址是必要的。但是,我们配置这个IP地址的唯一目的也只是帮助BGP建立邻居关系,它并不会被通告进入整个网络中。此外,Clos网络中存在着大量的链路连接,那么意味着大量的IP地址需要规划和管理,这会给数据中心建设以及自动化带来较大的工作负担。那么,有没有一种方式能够在我们不需要在接口配置IP地址的情况下,依然能够让双方建立BGP对等体关系?这似乎是一个悖论。 第二,我们的ASN在BGP中配置的主要目的标识对等体双方建立的BGP会话是iBGP还是eBGP。那么,我们能否用另外一种方式来替代ASN,但是依然能够标识这个会话是iBGP和eBGP? 二、接口IP带来的弊端 在这里,我们进一步探讨一下在数据中心中规模下,配置接口IP地址会带来的弊端。以帮助我们了解为什么值得解决这个问题。 我们可以想象一个简单的两层Clos网络,有4个Spine节点和和32个Leaf节点,这是一个相当常见的网络。在这种结构下,每个Spine节点有32条下连链路,每个Leaf一条。因此,这需要4 * 32 * 2 = 256个IP地址(4个Spine * 32个接口 * 每个接口2个地址,每端一个)。如果Leaf数为96个,而不是32个,那么我们需要的接口IP地址总数将是4 * 96 * 2 = 768。随着我们扩大规模,例如16个Spine节点,地址总数将上升到16 * 96 * 2 = 3,072。虽然算法推导出这些IP地址是可能的,但它可能很笨重,容易出错。此外,它也会自动化代码编写变得更加棘手。对自动化有一定了解的朋友们一定知道,目前我们通常采取的一种非常常见的方法,也就是将接口地址存储为一组列表,然后在自动化程序中,从这些变量中读取具体的IP地址,以便将地址分配给接口。 虽然看着这种方式不错,但是在巨大规模的网络中,这并不是非常可取的一种方式。因为在规划IP以及配置IP的过程中都容易出现错误,比如,创建该列表本身就是一件不容易的事情。 三、什么是Unnumbered接口? 早期的网络架构师在这项设计中还探索了另一个分支:不为同一个节点的每个接口分配唯一的IP地址。自己在本地不唯一的IP地址的接口被称为“无编号(unnumbered)”接口。Unnumbered接口并不是说明接口没有IP地址,只是没有唯一的IP地址。进一步说,该接口会借用本台设备上其他接口的IP地址。但是,如果借用IP地址的接口失败,其IP地址就不能被借来使用了。为了避免接口突然丢失其IP地址,Unnumbered接口通常从环回(Loopback)接口借用IP地址。 那么不同的路由协议如何处理Unnumbered接口?ISIS很好理解,ISIS运行在链路层,并且通告TLV(Type-Length-Value)字段将拓扑信息和路由信息进行了完全分离,能够在unnumbered接口的情况下很好的运行。OSPF虽然运行在IP之上,但是依然有相应的方式,在特定的场景(串口)下允许通过unnumbered接口建立邻居关系。那么对于BGP呢? 四、BGP中的Unnumbered接口使用原理 BGP和OSPF虽然都运行在IP层上,但是OSPF建立邻居通常使用的是组播,也就是说它不需要直接了解去往邻居的IP路由,而是通过组播的Hello报文去发现邻居。相比之下,BGP则是通过TCP的方式单播与已知的邻居建立会话。这要求本端存在去往对端端路由。那么,如果本地和对端都是Unnumbered接口,由于不在同一个网段,是没有去往对端的路由的,因此是无法通过路由建立TCP连接。 目前看来,好像进入了无解的地步。这个时候我们就需要借用另外一个协议栈,来帮助我们完成目标(接口不配置IP地址,依然双方能够建立BGP邻居)。这个帮手就是IPv6。 首先,我们知道IPv6相比于IPv4来说,增加了链路本地地址(LLA)。该地址是链路自己生成,并且仅仅提供本链路的连通性。此外,为了了解链路对端的LLA,MAC地址,IPv6还提供了一种机制,被称为路由通告(Router Advertisement或RA)。一旦一个启用了IPv6的接口UP,就会周期性的向外通告RA报文,其中包含了自己的IPv6地址(包含LLA),以及MAC地址(如果需要)。那么,对端设备收到该RA报文之后,就会生成去往它邻居的LLA的路由,以及记录对应的MAC地址。因此,IPv6天然就能保证在无需手动配置IP的情况下,同一链路下的通信。 到这里,我们找到了正确的方向。也就是说,我们可以通过IPv6的LLA地址建立BGP邻居。那么,这个邻居关系是通过IPv6建立的,如果我们要在该邻居中传递IPv4报文可以吗?看似匪夷所思,但是实际上是可行的。具体的实现,在RFC5549中进行了定义,该能力被称为extended nexthop,需要对等体双方进行协商是否支持。注意,这和隧道没有任何关系。 图2:通过IPv6帮助建立BGP邻居并通告IPv4路由 图2展示了如何通过IPv6帮助建立BGP邻居并通告IPv4路由。详细来说,使用IPv6 LLA成功建立连接后,BGP会收到具有对等体通告的IPv4路由通告,例如10.1.1.0/24。如果BGP选择此路径作为达到10.1.1.0/24的最佳路径,它将此路由传递到路由信息数据库(RIB)进程,将下一跳设置为IPv6 LLA,此下一跳信息将在BGP UPDATE消息中标识。接下来,RIB进程发现该路由的下一跳是一个IPv6 LLA地址,将通过映射关系找到对应的MAC地址,例如是:00:00:01:02:03:04。接下来,RIB进程会添加一个ARP条目,169.254.0.1作为ip地址代替下一跳的IPv6 LLA(因为ARP仅仅适用于IPv4中),00:00:01:02:03:04是对应的MAC地址。其中169.254.0.1是默认的保留地址,不能更改。最终,路由和ARP表如下所示: ROUTE: 10.1.1.0/24 via 169.254.0.1 dev swp1 ARP: 169.254.0.1 dev swp1 lladdr 00:00:01:02:03:04 PERMANENT 总结一下,我们如何在不配置接口IP的情况下依然可以传递BGP ipv4路由:

2021icpc上海m

kruskal重构树套st表 #include<cstdio> #include<algorithm> #include<cmath> using namespace std; int st[200005][20],mx[200005][20],t; int val[200005]; int fa[200005]; int n,m,q; struct edge{ int u,v,w; bool operator < (const edge &A) const{return w < A.w;} }e[100005]; const bool cmp (const edge &a,const edge &b) { return a.w<b.w; } int get_f (int u) { if (fa[u]!=u) fa[u]=get_f(fa[u]); return fa[u]; } int qry (int ci,int cv) { for (int i=19;i>=0;i--) if (st[ci][i] && cv>=mx[ci][i]) ci=st[ci][i]; return cv+val[ci]; } void ins (int u,int v,int w) { if (u==v) return; t++; fa[u]=fa[v]=t; val[t]=val[u]+val[v]; mx[u][0]=w-val[u]; mx[v][0]=w-val[v]; st[u][0]=st[v][0]=t; } void build_st() { for (int i=1;i<20;i++) for (int j=1;j<t;j++) if (st[j][i-1]) { st[j][i]=st[st[j][i-1]][i-1]; mx[j][i]=max(mx[j][i-1],mx[st[j][i-1]][i-1]); } } int main() { scanf("

qt实现服务端连接多个客户端

一、结构设计 1,组成 二、编程实现 1,主界面类 1,创建服务端 server = new Server(this, port); connect(server, &Server::pixmapChange, this, &MonitorServer::receiveAnJianJiPixmap); connect(server, &Server::deviceErrorInfoChange, this, &MonitorServer::showDeviceErrorInfo); connect(server, &Server::receiveHeart, this, &MonitorServer::receiveHeart); 2,服务器类 1,监听 Server::Server(QObject* parent, int port) : QTcpServer(parent) { listen(QHostAddress::Any, port); //监听 } 2,创建套接字连接客户端 void Server::incomingConnection(qintptr socketDescriptor) { //只要有新连接就生成一个新的套接字 TcpClientSocket* tcpclientsocket = new TcpClientSocket(this); tcpclientsocket->setSocketDescriptor(socketDescriptor); //将新创建的套接字加入到客户端套接字列表中 tcpclientsocketlist.append(tcpclientsocket); //接收到tcpclientsocket发过来的更新界面的信号 connect(tcpclientsocket, &TcpClientSocket::clientDisconnected, this, &Server::slotclientdisconnect); connect(tcpclientsocket, &TcpClientSocket::receivePixmapMessage, this, &Server::receivePixmapMessage); connect(tcpclientsocket, &TcpClientSocket::receiveDeviceErrorMessage, this, &Server::receiveDeviceErrorMessage); connect(tcpclientsocket, &TcpClientSocket::receiveHeart, this, &Server::receiveHeartMessage); } 3,如果有客户端断开连接,将列表中的套接字删除 void Server::slotclientdisconnect(int descriptor) { for (int i = 0; i < tcpclientsocketlist.

CMMI2.0之我见-原因分析和解决CAR&决策分析和解决DAR

编者按: CMMI2.0之我见系列将通过系列文章形式介绍CMMI2.0所涉及到的其中20个实践域,笔者将通过系统性的梳理、浅显易懂的文字描述,同时结合笔者的思考和观点,对每个实践域的目标以及所基本涵盖的内容进行描述,希望能抛砖引玉、相互碰撞,燎原出契合读者各自心中的答案。 目录/CONTENT 01 策划PLAN 02 风险与机会管理RSK 03 估算EST&监视与控制MC 04 组织级培训OT&供应商协议管理SAM 05 需求开发和管理RDM 06 验证和确认VV&同行评审PR 07 技术解决方案TS&产品集成PI 08 原因分析和解决CAR&决策分析和解决DAR 09 配置管理CM 10 过程管理PCM&过程资产开发PAD 11 管理性能和度量MPM 12 治理GOV&实施基础条件II 13 过程质量保证PQA CMMI2.0之我见-原因分析和解决CAR&决策分析和解决DAR 原因分析和解决CAR 原因分析和解决(CAR)是识别选定结果的原因并采取行动,防止错误的过程和结果再次发生,同时采取纠正措施或预防措施。 在CMMI1.3模型中这个实践域属于高等级过程域,只有实施到高等级才会涉及,但在CMMI2.0版本中重新调整了它的定位,认识到原因分析的重要性,在诸多环节上都离不开原因分析,让它回归到了本质。 通过将原因分析和解决落实到项目的每个阶段,提前对缺陷与问题进行预防,这种方式将更为有效。如果我们仅仅依靠在缺陷与问题产生之后对其进行检测,这样的效率是极其低下的,同时也将耗掉更多的成本。 原因分析和解决是项目间沟通经验教训的重要机制,通常需要对结果的类型进行分析,重要的是需要识别趋势。例如:基于CMMI模型,对已定义的过程及其如何实施的理解,确定这些结果的根本原因及其将来的影响。 因为对所有结果执行原因分析并不现实,所以通过对质量、生产率与周期时间的估算投入与回报进行权衡分析,选择需要执行原因分析的对象。 根因分析活动中,重点分析问题是怎么发生的,例如对于客户投诉还需要考虑产生根源在哪?也就是是否有完备的措施进行规避。如果分析产生的原因和流出根源还了解不够深入,必要时要上升至公司层面来关注如何规避问题,需要审视流程上是否存在漏洞与可优化点。 流程的优化并不一定是大刀阔斧的改动,流程优化可以是系统的,全面的,富有意义的,也可以是一个细节的补充和完善,也许同样可以解决大问题。根因分析之所以重要,同医生对症下药一个道理,根因分析得准确,措施才能自然而然的形成。 通常措施要与根因相对应,每一条根因至少有一或多条纠正预防措施,产生原因和流出原因对应纠正措施,系统原因可对应预防措施。 原因分析的主要使用场景举例: 1、问题或失败反复多次出现时,同样的问题多次在项目或者组织执行中出现。 2、项目实施、组织改进执行过程中明显与计划目标或需求发生偏移时。 3、测试阶段BUG的数量及比例远远高于预期时。 4、过程性能目标超出或低于预期时。 5、某一改进流程执行结果不能够满足预期质量与过程性能目标时。 下面主要介绍一下根本原因分析的常用方法及步骤: 鱼骨图分析法首当其冲,鱼骨图又名石川图,发明者是日本管理大师石川馨。鱼骨图是一种发现问题“根本原因”的方法,它也可以称之为“因果图”。鱼骨图主要用于各类管理中的建立分析模型。 鱼骨图分析法是进行因果分析时经常采用的一种方法,其特点是简捷实用,比较直观。鱼骨图实施的主要分析步骤是: ①分析结构:针对问题点,甄别不同层别的方法,例如:人、机、料、法、环等,按头脑风暴分别对各层别、类别找出所有可能原因,将找出的各要素进行归类、整理,明确其从属关系,分析选取重要因素,检查各要素的描述方法,确保语法简明、意思明确。 ②分析要点:确定主要原因时,实施方面一般从“人、机、料、法、环”着手,管理类问题一般从“人、事、时、地、物”层别,应视具体情况决定,主要原因需用中性词描述,不说明好坏,其他次要的原因可以使用价值判断。 需要尽可能多而全地找出所有可能原因,而不仅限于自己能完全掌控或正在执行的内容。另外从对人的原因分析方面,应该从行动而非思想态度面着手分析,理清其中的问题关系,如果某种原因可同时归属于两种或两种以上因素,需要以关联性最强者为准。例如:场景化还原现场,通过相对条件的比较,找出相关性最强的要因归类。最后在选取重要原因时,应标识在鱼骨刺的最末端。 ③使用步骤:首先查找要解决的问题,把问题写在鱼骨的头上,召集同事共同讨论问题出现的可能原因。另外尽可能多的找出问题,把相同的问题分组,在鱼骨上标出,根据不同问题征求大家的意见,总结出正确的原因。 最后拿出任何一个问题,研究为什么会产生这样的问题,针对问题的答案再问为什么?这样至少深入五个层次,当深入到第五个层次后,认为无法继续进行时,列出这些问题的原因,同时需要列出多个解决方法。 决策分析和解决DAR 决策分析和解决的目的在于利用正式的评判标准流程,依据已建立的准则评估各种已识别的备选方案,分析可能的决策。 决策分析和解决实践域包含建立指导,利用正式评审过程,依据已建立的准则,评估已识别的多种备选方案,以分析可能的决策,确定最佳解决方案。 正式的决策流程减少了决策的主观性,提高了决策的科学性。定义清晰决定什么议题需要正式评估过程,然后引用正式评判过程解决议题。正式评判过程为结构化的方法,依据已建立的准则评估备选解决方案,并决定最终的方案来解决议题。 在CMMI2.0中决策分析这个实践域也有一些改变,例如:决策分析的条件进行了增加,包括风险,变更,质量,进度,团队氛围等方面的考虑,同时由1.3版本中的6个实践,精简合并变成5个实践。即将”评价候选方案”和”选择解决方案”进行了合并,变为“使用准则和方法评价并选择解决方案”。 决策分析可以应用于选定技术的重要事项上,正式评判过程也可应用于许多非技术的议题,特别当项目开始规划,议题有多种备选解决方案与评估准则时,例如人的选择,物的选择,环境的配置等等,适合使用正式评判过程。 而大多数的设备选择或软件技术的替代方案研究是正式评判过程的典型范例。再举例:在项目策划期间,识别哪些特定议题需要正式评估过程。典型的议题包括:选择架构或设计的备选方案、使用复用或现成品组件、选择供应商、工程支持环境或相关工具、测试环境、交付的备选方案等。 在项目实施过程中,技术方案选型往往是比较揪心的一个过程,需要在满足需求、技术先进性、成熟度、成本、人力、工期等方面进行平衡,而且这些方案是项目干系人和项目组成员在头脑风暴会议上,通过快速互动、刺激提出有创意的备选技术解决方案。每个方案都有意义,或者说多数的方案都是能解决问题,只是成本、时间、人力等方面的目标一致性需要统一衡量。 其他非技术的包括:自行开发或采购的决策、过程的开发、产品定位的选择及其它决策。在使用决策分析时需要建立指导原则和进入和退出准则,以决定何时使用正式评判过程来解决非计划中的这些议题。 当议题涉及中高风险或议题会影响达成项目目标的能力时,通常建议使用正式评判过程。正式评判过程有不同的形式、准则类型及使用的方法,例如:不正式的决策,其分析可能花费几小时、只使用几条准则、人员投入决策的工作量很少,以及产生一两页报告。 但是较正式的决策可能需要具体的计划、一定的工作量投入、制定与确定准则的会议、模拟、原型等。 评判的标准如何定义?正式评判过程可使用量化或非量化的准则。量化准则使用权重以反映准则的相对重要性;非量化准则使用较主观的等级划分,如:高、中、低。较正式的决策可能要求完整的替代方案,需要识别与评估各种备选解决方案。 另外在评判期间,已识别的备选方案,可能被重新组合、新技术也可能改变备选方案,供应商的资质情况在评估期间也可能改变,所以建议备选方案在评审之前需要有充分的理解和研判。 最后我想强调一点是在决策过程中如能够量化的,尽可能的拿数据进行说话,目前许多企业在决策时仍沿用以往的个人经验,没有数据,这在实际决策运行时会出现很多问题。 在数据分析行业发展成熟的国家,90%的市场决策和经营决策都是通过数据分析研究确定的。用数据说话,重视定量分析,也逐渐成为科学研究、企业经营、政府决策等过程着重考虑的问题,越来越多的人们意识到基于数据分析的决策对公司经营的重要意义。 更多精彩内容和视频,请关注同名微信公众号。

java ThreadPoolExecutor线程池的使用

笔记: java ThreadPoolExecutor线程池的使用 1 为什么使用线程池?2 创建线程池3 执行任务 1 为什么使用线程池? (1) 大量线程的创建和销毁会过度消耗系统资源 (2) 节省系统响应时间, 如果要处理请求, 而线程池中恰好有空闲的线程, 那么就可以直接处理, 无需创建新的线程; 不仅节省了系统资源, 无形中也缩减了响应请求的时间 (3) 控制程序创建线程的数量, 通过设置线程池最大线程数限制线程数量, 防止线程过多导致系统崩溃 2 创建线程池 使用静态代码块创建一个线程池 private static ExecutorService singleThreadPool; static { ThreadFactory namedThreadFactory = new ThreadFactoryBuilder() .setNameFormat("demo-pool-%d").build(); singleThreadPool = new ThreadPoolExecutor( 5, 5, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(2048), namedThreadFactory, new ThreadPoolExecutor.CallerRunsPolicy()); } ThreadFactory : 线程工厂 ThreadFactoryBuilder: 使用ThreadFactoryBuilder创建一个带有名字的线程, 便于发生异常时的排查 ExecutorService: ExecutorService接口继承自Executor接口,提供了管理终止的方法,以及可为跟踪一个或多个异步任务执行状况而生成 Future 的方法。 增加了shutDown(),shutDownNow(),invokeAll(),invokeAny()和submit()等方法。如果需要支持即时关闭,也就是shutDownNow()方法,则任务需要正确处理中断。 ThreadPoolExecutor: 一个ExecutorService的实现 构造方法: ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) corePoolSize: 线程池核心线程数

2022年年终总结

目录 2022年做了什么?生活方面工作方面学习方面 2022年的反思2023年的打算 2022年做了什么? 生活方面 宝宝健康成长 孩子在老家主要由老婆带着,我一个人仍是在上海打工。由于家里面在家的人少,孩子是一刻也离不开妈妈了。一会儿见不到妈妈,就开始着急要妈妈了。 孩子主要拉臭臭不行,半年了还是一周才拉一次了,而且还要打开塞露才行,但是打开塞露不是个办法。开始是吃益生菌,后来是吃乳果糖,后来是吃中药。吃着药的话,还能隔一天拉一次;药一停,就不拉了。后来,老家里面疫情严重,连中药也没得吃了,只好去买点益生菌吃,孩子竟然自己开始一天一拉,或者隔天一拉了。真不容易啊,这个事情快把妈妈愁死了。因为不拉臭臭这个事情,妈妈观察到孩子尾椎骨地方有一个小针眼儿,看网上说这个情况有可能是脊髓栓系,可能要做手术;然后带着孩子去做了核磁共振,还好不是网上说的这种情况。 十一的时候回家,带孩子的时候,孩子一不小心滑倒,直接后脑勺着地了。当天晚上,就精神不好,想睡觉了,一直叫妈妈;第二天,发现孩子走路都有些不稳了,去村里面的医生那里看看,医生说没有事情,不用担心;到晚上,妈妈还是不放心,急得团团转,生怕孩子真的摔到什么地方了。就包了一个车去市里面给孩子做 CT 了,还好没有问题。回来的时候,已是凌晨2点了,岳母还在家等着我们了。 由于很少回家,所以每次跟家里视频的时候,会录下一些视频,自己有空就看看。有了这些视频,也可以随时打开看看孩子,不觉感到生活是多么有希望的一件事情。这些视频,也记录着孩子一天一天长大的过程了:孩子会叫妈妈了,孩子第一次摇摇晃晃地学步,孩子可以走十几步了,孩子会叫爸爸了,孩子会学着说话了,孩子专心在看书听故事,孩子在发脾气,…。 疫情 由于疫情,今年回家次数太少了。清明,五一的时候,上海封控,没有回去。在 7 月份抽空回去了一趟。中秋,十一都回去了。元旦离过年很近了,现在疫情大范围传播,也没有回去了。 12 月中旬,自己也感染了新冠。居家办公了一周后,抗原转阴。回到公司后,发现好多人都感染了。新冠的后遗症是咳嗽,心脏不舒服,心脏有点发闷,不敢深呼吸。 房子装修完成 房子在二舅哥的主导下装修在八月份全部装修完成了。房子装修花了不少钱,真的是花钱如流水啊。由于疫情,一直没有去看装修好的房子。 工作方面 工作方面比较大的变化是换了岗位了,11 月上旬从 Android 开发转岗到 C 开发了。 1月份-3月份 开发并维护一个车厂的下载项目。按说是很简单的一个项目,只是实现下载功能而已,连页面都没有。但是,前前后后沟通花费了不少时间。给我留下深刻印象的有两点,一是公司的下载库竟然有下载会卡住的问题,也号称是一个稳定的库;二是跟客户沟通的内容要文档化,避免后面扯皮,也正是因为自己做了需求文档化的工作,后面客户无端改需求提变更的时候,才可以给他们强力的反击。 另外,就是维护一些旧的车厂项目了,没有什么可以说的。和之前一个同事聊天,问他们公司怎么快速把 excel 表格里面的多语言话术转为 xml 的,才知道他们是使用一个 python 工具转的。然后,自己写了一个 kotlin 的转换小程序,也实现了同样的功能,并应用在项目中了。 4月份-6月份 这一段时间是上海疫情封控的三个月,自己居家办公了三个月。主要是处理了一些车厂提出的问题以及需求。说实话在家里面工作上还是比较闲的。 7月份到9月份 一个车厂的项目又重新开始开发了。自己帮忙改了需求,以及修改问题。没有什么好说的。 这段时间自己主要是学习并在项目中实践了 Android 单元测试。关于如何入门单元测试,自己也分享了一篇文章:Android实战——单元测试从吹水到实践。 10月份 10 月份自己向领导提了转岗的想法。领导同意了过渡式转岗的方式。这个月自己一方面交接自己的项目给同事,一方面再学习一些 C 语言方面的东西。 转岗的想法,其实是在刚来到车联网部的时候,就已经有了。看到在车联网部,继续做 Android,再过几年也不会有任何起色:学的东西用不上,小组内部学习氛围差,业务需求无挑战。另外,觉得自己这几年做 Android,一直在这个公司呆着,技术上进展很慢,即便出去找,也没有竞争力了。总之,是想改变一下吧。 11月份和12月份 转岗过渡期,来到公司合肥这边的研发中心。一边做着一些 Android 之前的工作,其实本来 Android 就没有多少工作;一边进行转岗学习:主要承担一些基础的开发工作,如数据解析,数据上报,业务需求的理解,一些知识的补充。 转岗是不容易的。C 开发的知识需求和 Android 开发的知识需求大相径庭。C 开发需要掌握 Linux 知识,CMake,C 语言,以及处理一些编译问题,这些东西在做 Android 的时候可以说接触的非常少。

一文轻松明白 Base64 编码原理

把图片丢进浏览器,打开sources能看到一长串字符串,这是图片的Base64编码。这一长串编码到底是怎么生成的呢? 我们接下来探索一下base64编码的原理 Base64 名称的由来 Base64编码要求把3个8位的字节(38=24)转化为4个6位的字节(46=24),之后在6位的前面补两个0,形成8位一个字节的形式。如果剩下的字符不足3个字节,则用0填充,输出字符使用’=‘,因此编码后输出的文本末尾可能会出现1或2个’='。 为了保证所输出的编码位可读字符,Base64制定了一个编码表,以便进行统一转换。编码表的大小为2^6=64,这也是Base64名称的由来。(下面是Base64编码表) 思路 原始数据对应ASCII,生成8位的二进制,3个8位的字节(38=24)转化为4个6位的字节(46=24),不够补零。分割之后,得出来6位字节的二进制转化成十进制,再从base64表中寻找对应的字符 实现过程 原始数据:Mz1 根据ASCII表转换成8位二进制:01001101 | 01111010 | 00110001 将 38 切割成 46:010011 | 010111 | 101000 | 110001 分别转化成十进制:19 | 23 | 40 | 49 最后再去Base64编码表中找到数字对应的字符:T | X | o | x 最终 Mz1 的 Base64 :TXox 强化训练 Q:写出TB对应的Base64编码 1.TB1 对应的ASCII T:01010100 B:01000010 1:00110001 2.将三个8位的二进制分割成4个6位的二进制 010101 000100 001000 110001 3.将二进制转换成十进制 21 4 8 49 4.将十进制按照Base64表得到Base64编码 V E J x A:TB1所对应的Base64编码为 VEJx 用Base64的来呈现图片的有什么优势呢? 1)减少http网络请求:网页上的图片资源如果采用http形式的url的话都会额外发送一次请求,网页发送的http请求次数越多,会造成页面加载速度越慢。而采用Base64格式的编码,将图片转化为字符串后,图片文件会随着html元素一并加载,这样就可以减少http请求的次数,对于网页优化是一种比较好的手段。

C++ 蛇形矩阵

蛇形矩阵 (C++) 输入两个整数 n n n和 m m m,输出一个 n n n行 m m m列的矩阵,将数字 1 1 1到 n × m n×m n×m按照回字蛇形填充至矩阵中。 具体矩阵形式可参考样例。 输入格式 输入共一行,包含两个整数 n n n和 m m m。 输出格式 输出满足要求的矩阵。 矩阵占 n n n行,每行包含 m m m个空格隔开的整数。 数据范围 1 ≤ n , m ≤ 100 1≤n,m≤100 1≤n,m≤100 输入样例: 3 3 输出样例: 1 2 3 8 9 4 7 6 5 代码: #include <iostream> using namespace std; const int N = 110; int main() { int n, m, a, b; cin >> n >> m; int Q[N][N]; int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1}; int x = 0, y = 0, d = 1; for(int i = 1 ;i <= n*m; i++) { Q[x][y] = i; a = x + dx[d]; b = y + dy[d]; if(a < 0||a >= n||b < 0||b >= m||Q[a][b]) { d = (d+1) % 4; a = x + dx[d]; b = y + dy[d]; } x = a; y = b; } for(int i = 0; i < n; i++) { for(int j = 0; j < m ; j++) { cout << Q[i][j] << "

wsl ubuntu linux环境变量重复 环境变量不生效source .profile source .bashrc

source命令 source .profile source .bashrc 在同一个shell窗口中,每source一次.profile或者.bashrc,自定义的环境变量就会再添加一次,$PATH越来越长,此时重新打开一个窗口就会恢复正常,但是有时会发现刚才添加的环境变量在新的shell窗口中没有生效,还要执行source命令 因为source命令更新的环境变量是临时起作用,只在当前shell中生效。 .profile文件 如果使用.profile文件添加环境变量,想要永久生效,就必须重新登录当前用户。 也可以在其他环境变量文件中添加source .profile命令,但是实际上,在没有重新登录的情况下,这并不是永久生效,只是每一次你不用手动输入source命令,它每次自动执行了而已。 .bashrc文件 在.bashrc中添加环境变量,每次打开shell窗口都会执行一次,也不属于永久生效,因为在.profile或者.bash_profile中存在读取.bashrc的命令,如下,如果在.bashrc中添加的环境变量没有自动生效,那就在.profile或者.bash_profile中添加如下代码。 # if running bash if [ -n "$BASH_VERSION" ]; then # include .bashrc if it exists if [ -f "$HOME/.bashrc" ]; then . "$HOME/.bashrc" fi fi

win10搭建 IIS 服务器

第一步: 打开程序和功能 找到 Internet 这个 勾选web管理工具和万维网服务 第二步: 在本地电脑创建一个文件夹(不要有中文空格等特殊字符) index.html 是默认访问的网址 第三步 关联访问的链接 选择本地物理路径 访问测试 第四步 修改绑定端口 第五步 修改防火墙 添加名称 到这里IP 加端口访问已经完成 下面将ip和端口映射到网址上 修改windows 下面的host 在本地 C:\Windows\System32\drivers\etc 路径下 如果设置这个 只能在在本地访问 并且访问 时输入 www.xxx.com :xxxx端口 如果想在另一台电脑上使用www.xxx.com:xxxx访问 则需要同样配置host

Codeforces Round #833 (Div. 2)E. Yet Another Array Counting Problem(笛卡尔树+树形DP)

题目链接:Problem - E - Codeforces 样例输入: 4 3 3 1 3 2 4 2 2 2 2 2 6 9 6 9 6 9 6 9 9 100 10 40 20 20 100 60 80 60 60 样例输出: 8 5 11880 351025663 题意:给定一个长度为n的数组a[],对于每一个区间[l,r],这个区间的leftmost定义为区间[l,r]中的值等于该区间内元素的最大值的最小下标,现在问我们有多少种长度为n的数组b[],满足对于任意区间都有leftmost值等于数组a的对应区间的leftmost值,且b数组中的元素值是介于1到m之间的。 分析:其实这道题要先知道笛卡尔树这个预备知识。 笛卡尔树是二叉排序树和堆的结合。 对于一个笛卡尔树,对笛卡尔树进行中序遍历即可得到原序列。 笛卡尔树中每个节点的左子树上的节点的坐标都是小于该节点的,右子树上的节点的坐标都是大于该节点的。而且每个节点的值是大于/小于其子树上的节点的值的,这个取决于是和大根堆结合还是和小根堆结合。 对于这道题目而言,我们就让根节点的值大于其左子节点的值,大于等于其右子节点的值,那么对于a数组和b数组需要构造出相同形态的笛卡尔树才算是满足题意的。所以我们可以按照a数组构造出笛卡尔树,然后利用树形DP向每个节点进行填值求方案数即可。 建树的过程,可以发现 每个右子树根节点的父亲节点就是他左边第一个大于他的数的位置 每个节点的左子树根节点就是他左边小于该值的数中的最大值的最小下标 这个显然可以用单调栈来维护,那么建树复杂度就是O(n),细节可以见代码 最后就是根据笛卡尔树求解方案数了。 设f[x][y]代表x节点取值为1~y时的方案数和。那么更新过程就有四种情况: x节点有左右子树,那么就有f[x][y]=f[x][y-1]+f[l[x]][y-1]*f[r[x]][y] x节点只有左子树,那么就有f[x][y]=f[x][y-1]+f[l[x]][y-1] x节点只有右子树,那么就有f[x][y]=f[x][y-1]+f[r[x]][y] 如果没有孩子节点,直接返回y 利用这个方法我们即可完成本道题目的更新。 #include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #include<map> #include<queue> #include<vector> #include<cmath> using namespace std; const int N=2e6+10,mod=1e9+7; int l[N],r[N],fa[N]; int s[N],top; long long f[N],v[N]; int n,m; void build(int n) { top=0; for(int i=1;i<=n;i++) r[i]=l[i]=0; for(int i=1;i<=n;i++) { scanf("

BootCDN——React入门学习

首先下载:react依赖:react.js、react-dom.js、babel.js 这种方式容易出错,所以不使用这个 使用下面方式正真的用法;Babel 中文网 · Babel - 下一代 JavaScript 语法的编译器

C/C++中的pi(pai)怎么打 【c语言】

极速版: const double pi = acos(-1.0); 详细版: 函数名: acos 功 能: 反余弦函数 自变量范围:在 -1~1 之间 因变量范围:返回的是一个数值的反余弦弧度值,其范围是 0~ pi 。 头文件:<math.h> 测试代码: #include<bits/stdc++.h> using namespace std; const double pi = acos(-1.0); int main(){ for(double i = -1; i<=1; i=i+0.25){ printf("%.64lf\n", acos(i)); } return 0; } 参考: acos_百度百科 (baidu.com) 

SSH连接虚拟机失败

sshcilent连接虚拟机失败 在重启电脑之后突然发现SshClient无法连接上我的虚拟机。(NAT模式) 在cmd尝试ping虚拟机发现无法ping通,但是在虚拟机内可以ping到我的主机地址。 在尝试过关闭防火墙,重启网络等方法后,找到了解决方法 在控制面板中找到网络连接里的VMnet8,将 的属性改写为 重启连接后即可进行正常的连接。

【vector的各个begin迭代器详解】

前言 本文是熊猫练习stl一段时间之后,对vector容器的各种迭代器产生了很大的好奇心,于是对它们进行了以下探究。 从图中我们可以知道,vector一个有四组不同的迭代器, 其中,字符 ‘c’ 是 const 常量的意思,既所指向的对象不能修改, 字符 ’ r ’ 是 reverse 反转的意思,既从后往前遍历数据。 注意:rbegin() 迭代器的操作和它的名字一样:是反向的,与我们平时的理解不一样,eg: rit = rbegin(); rit++; 这里的rit相当于指向最后一个位置的数据的指针, rit++;表示指针向后走一步, 按照我们平时的理解:此时rit指向最后一个数据的下一个位置, 然而实际上:此时rit指向最后一个数据左边的位置,也就是 “2022”的第二个 2, 这也就是reverse 反转的特点,迭代器从后往前进行遍历。 void test06() { vector<int>v1; for (int i = 0; i < 10; ++i) { v1.push_back(i); } // 不同的返回值需要使用对应的迭代器接收 vector<int>::iterator it; // 迭代器 vector<int>::const_iterator cit; // 常量迭代器 vector<int>::reverse_iterator rit; // 反向迭代器 vector<int>::const_reverse_iterator crit; // 常量反向迭代器 // begin cout << "begin:" << endl; it = v1.