c++矩阵连乘的动态规划算法并输出_算法面试必修课,动态规划基础题型归纳(三)

70cc93277a9c3af68da48b13e2d030d8.png

动态规划(Dynamic Programming,简称DP),是大家都觉得比较难以掌握的算法。为了应付面试,我们经常会背诵一下DP问题的源码,其实,只要理解了思想,掌握基本的模型,然后再来点写代码的套路,动态规划并没有那么难。

先来回顾一下题型目录。

动态规划基本题型总结提纲目录

1.硬币找零,路径规划

2.字符串相似度/编辑距离(edit distance)

3.最长公共子序列(Longest Common Subsequence,lcs)

4.最长递增子序列(Longest Increasing Subsequence,lis)

5.最大子序列积

6.矩阵链乘法

7.0-1背包问题

8.有代价的最短路径

9.瓷砖覆盖(状态压缩DP)

10.工作量划分

11.三路取苹果

上篇文章讲到第五个题型,最大子序列积,这篇从第六个题型开始。

6.矩阵链乘法

先看矩阵乘法

a89f589833934e5acef28cfe6571e7da.png

从定义可以看出:只有当矩阵A的列数与矩阵B的行数相等时A×B才有意义。一个m×r的矩阵A左乘一个r×n的矩阵B,会得到一个m×n的矩阵C。在计算机中,一个矩阵说穿了就是一个二维数组。一个m行r列的矩阵可以乘以一个r行n列的矩阵,得到的结果是一个m行n列的矩阵,其中的第i行第j列位置上的数等于前一个矩阵第i行上的r个数与后一个矩阵第j列上的r个数对应相乘后所有r个乘积的和。

所谓矩阵链乘法是指当一些矩阵相乘时,如何加括号来改变乘法顺序从而来降低乘法次数。例如有三个矩阵连乘:A1*A2*A3,其维数分别为:10*100,100*5,5*50.如果按照((A1*A2)A3)来计算的话,求(A1*A2)要10*100*5=5000次乘法,再乘以A3需要10*5*50=2500次乘法,因此总共需要7500次乘法。如果按照(A1(A2*A3))来计算的话,求(A2*A3)要100*5*50=25000次乘法,再乘以A1需要10*100*50=50000次乘法,因此总共需要75000次乘法。可见,按不同的顺序计算,代价相差很大。

比如对于这个M₁M₂M₃的矩阵链,

470396470b87d9fabce36ed3b92bafc1.png

我们可以先计算M₁M₂然后结果乘以M₃,也可以M₂M₃先算,然后乘以M₁,为了表达方便,可以用括号表示计算顺序。 矩阵链M₁M₂M₃有两种计算顺序:((M₁M₂)M₃)和(M₁(M₂M₃))。 那么不同计算顺序有什么区别? 对于((M₁M₂)M₃):

f228d9001130cc906d2f23826986c284.png

对于(M₁(M₂M₃)):

1a54b61f07fb8aa6d41c189e3094e3f4.png

我们要做的就是找到让乘法运算最少的计算顺序,换言之就是找一种加括号方式,使得最后乘法运算最少。

矩阵链乘法问题可以表述如下:给定n个矩阵构成的一个链(A1*A2*A3……*An),其中i=1,2,……n,矩阵Ai的维数为p(i-1)*p(i),对于乘积A1*A2*A3……*An以一种最小化标量乘法次数的方式进行加括号。

这个问题太难理解了。

为了代入问题,先来朴素算法,这个总能看懂吧。

void mult(int a[MAXN][MAXN],int b[MAXN][MAXN],int c[MAXN][MAXN],int p,int q,int r)  
{  int i,j,k;  //先对c进行初始化  for(i=0;i<p;i++)  {  for(j=0;j<r;j++)  {  c[i][j] = 0;  }  }  //计算矩阵乘法  for(i=0;i<p;i++)  {  for(j=0;j<r;j++)  {  for(k=0;k<q;k++)  {  c[i][j] += a[i][k] * b[k][j];  }  }  }  
}  

解决这个问题,我们可以用穷举法,但是n很大时,这不是个好方法,其时间复杂度为指数形式。拿上面的例子来说,加括号后把矩阵链分成了两部分,计算代价为两者代价的和。因此假设这种方法的代价最少,则两个部分的代价也是最小的,如果不是最小的,那么这种方法就不是最优的,因此矩阵链乘法具有最优子结构。因此我们可以利用子问题的最优解来构造原问题的一个最优解。所以,可以把问题分割为两个子问题(A1*A2*A3……*Ak和A(k+1)*A(k+2)*A(k+3)……*An),需找子问题的最优解,然后合并这些问题的最优解。从下面的程序可以看出,其时间复杂度为n*n*n.

题目分析:

递推关系:

设计算A[i:j],1≤i≤j≤n,所需要的最少数乘次数m[i,j],则原问题的最优值为m[1,n]。

当i=j时,A[i:j]=Ai,因此,m[i][i]=0,i=1,2,…,n

当i<j时,若A[i:j]的最优次序在Ak和Ak+1之间断开,i<=k<j,则:m[i][j]=m[i][k]+m[k+1][j]+pi-1pkpj。由于在计算是并不知道断开点k的位置,所以k还未定。不过k的位置只有j-i个可能。因此,k是这j-i个位置使计算量达到最小的那个位置。

综上,有递推关系如下:

58078df6aa99cdec83744fd907be70ba.png

构造最优解:

若将对应m[i][j]的断开位置k记为s[i][j],在计算出最优值m[i][j]后,可递归地由s[i][j]构造出相应的最优解。s[i][j]中的数表明,计算矩阵链A[i:j]的最佳方式应在矩阵Ak和Ak+1之间断开,即最优的加括号方式应为(A[i:k])(A[k+1:j)。因此,从s[1][n]记录的信息可知计算A[1:n]的最优加括号方式为(A[1:s[1][n]])(A[s[1][n]+1:n]),进一步递推,A[1:s[1][n]]的最优加括号方式为(A[1:s[1][s[1][n]]])(A[s[1][s[1][n]]+1:s[1][s[1][n]]])。同理可以确定A[s[1][n]+1:n]的最优加括号方式在s[s[1][n]+1][n]处断开…照此递推下去,最终可以确定A[1:n]的最优完全加括号方式,及构造出问题的一个最优解。

动态规划迭代实现

用动态规划迭代方式解决此问题,可依据其递归式自底向上的方式进行计算。在计算过程中,保存已解决的子问题的答案。每个子问题只计算一次,而在后面需要时只需简单检查一下,从而避免了大量的重复计算,最终得到多项式时间的算法。

代码如下:

//3d1-2 矩阵连乘 动态规划迭代实现  
//A1 30*35 A2 35*15 A3 15*5 A4 5*10 A5 10*20 A6 20*25  
//p[0-6]={30,35,15,5,10,20,25}  
#include "stdafx.h"  
#include <iostream>   
using namespace std;   const int L = 7;  int MatrixChain(int n,int **m,int **s,int *p);   
void Traceback(int i,int j,int **s);//构造最优解  int main()  
{  int p[L]={30,35,15,5,10,20,25};  int **s = new int *[L];  int **m = new int *[L];  for(int i=0;i<L;i++)    {    s[i] = new int[L];  m[i] = new int[L];  }   cout<<"矩阵的最少计算次数为:"<<MatrixChain(6,m,s,p)<<endl;  cout<<"矩阵最优计算次序为:"<<endl;  Traceback(1,6,s);  return 0;  
}  int MatrixChain(int n,int **m,int **s,int *p)  
{  for(int i=1; i<=n; i++)  {  m[i][i] = 0;  }  for(int r=2; r<=n; r++) //r为当前计算的链长(子问题规模)    {  for(int i=1; i<=n-r+1; i++)//n-r+1为最后一个r链的前边界    {  int j = i+r-1;//计算前边界为r,链长为r的链的后边界    m[i][j] = m[i+1][j] + p[i-1]*p[i]*p[j];//将链ij划分为A(i) * ( A[i+1:j] )   s[i][j] = i;  for(int k=i+1; k<j; k++)  {  //将链ij划分为( A[i:k] )* (A[k+1:j])     int t = m[i][k] + m[k+1][j] + p[i-1]*p[k]*p[j];  if(t<m[i][j])  {  m[i][j] = t;  s[i][j] = k;  }  }  }  }  return m[1][L-1];  
}  void Traceback(int i,int j,int **s)  
{  if(i==j) return;  Traceback(i,s[i][j],s);  Traceback(s[i][j]+1,j,s);  cout<<"Multiply A"<<i<<","<<s[i][j];  cout<<" and A"<<(s[i][j]+1)<<","<<j<<endl;  
} 

7.0-1背包问题

题目描述:

有n个物品,它们有各自的体积和价值,现有给定容量的背包,如何让背包里装入的物品具有最大的价值总和?

为方便讲解和理解,下面讲述的例子均先用具体的数字代入,即:eg:number=4,capacity=8

e70fe268ad8acda472a53d36bd0d0b0c.png

有n个物品,每个物品有两个属性:一个是体积,一个是价值 ,可以表示为:(w1,v1),(w1,v1),…,(w1,vn) {(w_1,v_1 ),(w_1,v_1 ),…,(w_1,v_n )} )。同时我们还有一背包,背包的容量用W表示。现在我们将物品放入背包,放入的物品体积的总和不得超过背包的体积。

问:这个背包能装下的最大价值。

题目分析:

  ①、将原问题分解为子问题(子问题和原问题形式相同,且子问题解求出就会被保存);

  ②、确定状态:01背包中一个状态就是NN个物体中第ii个是否放入体积为VV背包中;

  ③、确定一些初始状态(边界状态)的值;

  ④、确定状态转移方程,如何从一个或多个已知状态求出另一个未知状态的值。(递推型)

思路:

①、确认子问题和状态

  01背包问题需要求解的就是,为了体积V的背包中物体总价值最大化,NN件物品中第ii件应该放入背包中吗?(其中每个物品最多只能放一件)

  为此,我们定义一个二维数组,其中每个元素代表一个状态,即前ii个物体中若干个放入体积为VV背包中最大价值。数组为:f[N][V]f[N][V],其中fijfij表示前ii件中若干个物品放入体积为jj的背包中的最大价值。

  ②、初始状态

  初始状态为f[0][0−V]f[0][0−V]和f[0−N][0]f[0−N][0]都为0,前者表示前0个物品(也就是空物品)无论装入多大的包中总价值都为0,后者表示体积为0的背包啥价值的物品都装不进去。

  ③、转移函数

if (背包体积j小于物品i的体积)f[i][j] = f[i-1][j] //背包装不下第i个物体,目前只能靠前i-1个物体装包
elsef[i][j] = max(f[i-1][j], f[i-1][j-Vi] + Wi)

  最后一句的意思就是根据“为了体积V的背包中物体总价值最大化,NN件物品中第ii件应该放入背包中吗?”转化而来的。ViVi表示第ii件物体的体积,WiWi表示第ii件物品的价值。这样f[i-1][j]代表的就是不将这件物品放入背包,而f[i-1][j-Vi] + Wi则是代表将第i件放入背包之后的总价值,比较两者的价值,得出最大的价值存入现在的背包之中。

01背包问题其实就可以化简为涂写下面的表格,其中每个数对应数组nArr中每个元素,初始化部分为0,然后从左上角按行求解,一直求解到右下角获取最终解nArr[5][12]。

656422e3ab3b48833da89e8120e64bc3.png

代码如下:

#include<iostream>
using namespace std;int main()
{int nArr[6][13] = {{0}};int nCost[6] = {0 , 2 , 5 , 3 , 10 , 4};  //花费int nVol[6]   = {0 , 1 , 3 , 2 , 6 , 2}; //物体体积int bagV = 12;for( int i = 1; i< sizeof(nCost)/sizeof(int); i++){for( int j = 1; j<=bagV; j++){if(j<nVol[i])nArr[i][j] = nArr[i-1][j];elsenArr[i][j] = max(nArr[i-1][j] , nArr[i-1][j-nVol[i]] + nCost[i]);       cout<<nArr[i][j]<<' ';}   cout<<endl;}cout<<nArr[5][12]<<endl;return 0;
}

再来看另外一个课件上的解释:

651f3f4efab025d13867bece9a98a6e2.png

背包问题是动态规划里面比较出名的题型,其变种题目很多,由于篇幅有限就不一一展开了,下面只列出背包问题的题型目录。

一、01背包问题

这是最基本的背包问题,每个物品最多只能放一次。

二、完全背包问题

第二个基本的背包问题模型,每种物品可以放无限多次。

三、 多重背包问题

每种物品有一个固定的次数上限。

四、 混合三种背包问题

将前面三种简单的问题叠加成较复杂的问题。

五、二维费用的背包问题

一个简单的常见扩展。

六、分组的背包问题

一种题目类型,也是一个有用的模型。后两节的基础。

七、 有依赖的背包问题

另一种给物品的选取加上限制的方法。

八 、泛化物品

九、 背包问题问法的变化

试图触类旁通、举一反三。

8.有代价的最短路径

从某顶点出发,沿图的边到达另一顶点所经过的路径中,各边上权值之和最小的一条路径叫做最短路径。解决最短路的问题有以下算法,Dijkstra算法,Bellman-Ford算法,Floyd算法和SPFA算法等。

现在只讨论Dijkstra算法。

1。指定一个节点,例如我们要计算 'A' 到其他节点的最短路径

2.引入两个集合(S、U),S集合包含已求出的最短路径的点(以及相应的最短长度),U集合包含未求出最短路径的点(以及A到该点的路径,注意 如上图所示,A->C由于没有直接相连 初始时为∞)

3.初始化两个集合,S集合初始时 只有当前要计算的节点,A->A = 0,

U集合初始时为 A->B = 4, A->C = ∞, A->D = 2, A->E = ∞,敲黑板!!!接下来要进行核心两步骤了

4.从U集合中找出路径最短的点,加入S集合,例如 A->D = 2

5.更新U集合路径,if ( 'D 到 B,C,E 的距离' + 'AD 距离' < 'A 到 B,C,E 的距离' ) 则更新U

循环执行 4、5 两步骤,直至遍历结束,得到A 到其他节点的最短路径

比如现在求A到E的最短加权路径,路径上的数值为权重。

92ad9576205e324ca28ad5b10e0b9c0b.png

1.选定A节点并初始化,如上述步骤3所示

5dd4c54211cf15c3cbf8071fa9a098ca.png

2.执行上述 4、5两步骤,找出U集合中路径最短的节点D 加入S集合,并根据条件if ( 'D 到 B,C,E 的距离' + 'AD 距离' < 'A 到 B,C,E 的距离' )来更新U集合。

746d8555e9f38a1c9be57090d66e3ee7.png

3.这时候A->B, A->C都为3,没关系。其实这时候他俩都是最短距离,如果从算法逻辑来讲的话,会先取到B点。而这个时候 if 条件变成了if ( 'B 到 C,E 的距离' + 'AB 距离' < 'A 到 C,E 的距离' )如图所示这时候A->B距离 其实为A->D->B

f44941639acfcb41c6c4ec93bb81e112.png

4.思路就是这样,往后就是大同小异了

f1c8b6a2bfda7c8c4d9e320e8ec9020d.png

5.算法结束

0e0e5166c7f36c9ebe48e8b778bdd0f5.png

大致步骤:

清除所有点的标号
全部d[i] = INF
然后将图信息权值复制到d中
循环n次{在所有为标号的结点中,选出d值最小的结点x给x标记对于从x出发的所有边(x,y),更新d[y] = min{d[y],d[y]+w(x,y)}

代码如下:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 500;
const int INF = 0x3f3f3f3f;
int n,m,dis[maxn],Map[maxn][maxn],v[maxn];
void dijkstra(int u)
{memset(v,0,sizeof v);memset(dis,INF,sizeof dis);v[u] = 1;for(int i = 1; i <= n; i++)dis[i] = min(dis[i],Map[u][i]);for(int i = 1; i <= n; i++){int x,m = INF;for(int y = 1; y <= n; y++)if(!v[y] && dis[y] <= m)m = dis[x = y];v[x] = 1;for(int y = 1; y <= n; y++)dis[y] = min(dis[y],dis[x]+Map[x][y] );}
}
int main()
{int a,u,v,w;scanf("%d%d%d",&n,&m,&a);memset(Map, INF, sizeof Map);for(int i = 0; i < m; i++){scanf("%d%d%d",&u,&v,&w);Map[u][v] = w;Map[v][u] = w; //该图为无向图,若为有向图则需要少建立一个边信息}for(int i = 1; i <= n; i++)Map[i][i] = 0;dijkstra(a);for(int i = 1; i <= n; i++)cout<<dis[i]<<" ";return 0;
}

动态规划还有最后几个题型,下篇会都说完。再后面我会分享贪心算法、回溯算法、分治算法,排序算法。欢迎一起学习。

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

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

相关文章

css 学习记录

如何引入css 内联样式 在标签内 添加style style标签 外联式写法 新建CSS文件 通过用link标签引入css样式文件 import url(../);、 css语法 选择器 {属性&#xff1a;值&#xff1b;} CSS属性 float的属性可以使元素左右浮动 设置字体的样式 color属性 用于 设置字体颜色 …

网站服务器睡眠后还能访问吗,远程服务器可以睡眠吗

远程服务器可以睡眠吗 内容精选换一换已成功添加Guardian。如果Guardian处于在线状态&#xff0c;只允许修改Guardian名称。如果Guardian处于连接超时状态&#xff0c;可以输入登录远程服务器的用户名和密码重新部署Guardian。如果Guardian处于在线状态&#xff0c;只允许修改G…

sql server如何输出排序序号_Group by中子查询order by排序失效问题分析

通过sql分组查询数据时&#xff0c;一般通过group by来完成&#xff0c;group by默认取相同的分组列(一列或者多列)中第一个数据。如果想获取sql分组中id最大的记录&#xff0c;我们可能想到的sql如下&#xff08;name列作为分组&#xff09;&#xff1a;select id,name from (…

深入学习Redis(1):Redis内存模型

前言 Redis是目前最火爆的内存数据库之一&#xff0c;通过在内存中读写数据&#xff0c;大大提高了读写速度&#xff0c;可以说Redis是实现网站高并发不可或缺的一部分。 我们使用Redis时&#xff0c;会接触Redis的5种对象类型&#xff08;字符串、哈希、列表、集合、有序集合&…

对话“互联网先驱”:星际互联网究竟可不可行?

Vinton Cerf曾在四十年前协助创造了互联网&#xff0c;如今他仍在努力帮助世界各地的人们建立联系。来源丨Quantamagazine作者丨Susan DAgostino编译丨科技行者Vinton Cerf&#xff0c;互联网之父之一&#xff0c;正在建立行星际互联网方面发挥着关键作用。太空探索困难重重&am…

烽火服务器怎么进入bios系统,装机高手告诉你如何进入bios

如何进入bios是很多装机技术人员才会研讨的问题&#xff0c;可是我们生活中依然有时分需求用到bios设置&#xff0c;这时分我们应该如何进入bios呢?说实话不同的电脑、型号都有不同的进入bios方法&#xff0c;但是关于主流的系统品牌来说&#xff0c;如何进入bios的方法大多都…

折弯弹性计算公式_冲压模具:影响回弹因素、回弹计算公式计算,值得收藏

回弹&#xff0c;设计师都会遇到&#xff0c;而且无法避免&#xff0c;只能想办法补偿或者降低影响。那什么是回弹呢&#xff1f;金属材料在塑性弯曲时总是伴随著弹性变形&#xff0c;因此当弯矩去掉之后&#xff0c;弯曲件的弯曲半径变得与模具尺寸不一致&#xff0c;这种现象…

image是否有disabled属性_Vue学习笔记 模板语法、计算属性

点击上方“蓝字”关注我们吧&#xff01;vue学习笔记官网&#xff1a;https://cn.vuejs.org/v2/guide/1、vue体验demo示例&#xff1a;image.png示例代码&#xff1a;<html lang"en"> <head> <meta charset"UTF-8" /> <meta n…

分析 | MEMS传感器市场报告

来源&#xff1a;核芯产业观察1、MEMS 发展迅速&#xff0c;Yole Development 预计 2023 年市场规模超 300 亿美元MEMS 全称为 Micro-Electro Mechanical System&#xff0c;即微机电系统&#xff0c;是集微型传感器、执行器、机械结构、电源能源、信号处理、控制电路、高性能电…

各大媒体优劣对比_信息流投放广告丨各大平台的信息流都有什么特点与弊端

相信很多企业都做过信息流的广告推广&#xff0c;那么各位广告主都做过哪些平台的信息流呢&#xff1f;今天我们来看一看各大平台的信息流都有什么特点与弊端吧&#xff01;1、社交类代表&#xff1a;微博粉丝通、广点通&#xff08;16年更名腾讯社交广告&#xff09;、陌陌、贴…

我们生活在一个虚拟世界的概率有多大?

© Thomas Leuthard - Flickr来源&#xff1a;人工智能AI技术利维坦按&#xff1a;我们在以前的文章中介绍过约翰惠勒提出的延迟实验&#xff1a;第一步&#xff1a;我们拿一块经过半镀银处理的反射镜BS1来代替双缝实验中的挡板。根据量子的分布随机性&#xff0c;从图示左…

mysql between and的用法的意思_从入门到入土:MySQL完整学习指南,包教包会!

一SQL 介绍SQL&#xff08;Structured Query Language&#xff09;,语义是结构化语言&#xff0c; 是一门 ANSI 的标准计算机语言&#xff0c;用来访问和操作数据库系统&#xff1b;二 数据库介绍2.1 数据库我们已经知道了SQL是操作数据库的语言&#xff0c;那么数据库是什么&a…

db2增加decimal类型字段小数位_05725.16.1Hive中decimal类型字段.0结尾数据显示异常问题处理...

作者&#xff1a;辉少1问题描述Fayson今天在Hive中插入字段类型为decimal的数据时发现&#xff0c;插入数据为1.0, 1.000等以 .0结尾的数据在hive中显示为1&#xff0c;即不显示末尾的.0 &#xff0c;如下&#xff1a;CREATE TABLE decimaltest (d decimal(18,7));INSERT INTO …

Nature:实验室培育的大脑可以拥有意识吗?

大数据文摘出品来源&#xff1a;nature编译&#xff1a;朱科锦、lin一直以来&#xff0c;对于科学家来说&#xff0c;人脑都是一个神奇的存在&#xff0c;关于人脑的研究也层出不穷。近几年&#xff0c;随着人工智能的发展&#xff0c;很多科学家都在努力探索&#xff0c;未来机…

c语言float转换为int_C语言的隐式类型转换和显示类型转换

C语言是一种强类型语言&#xff0c;当使用一种类型的对象代替另外一种类型的对象进行操作时&#xff0c;必须首先进行类型转换。类型转换的方式&#xff0c;一般可分为隐式类型转换和显示类型转换(也称为强制类型转换)。1、隐式类型转换隐式类型转换由编译器自动进行&#xff0…

asp 开发app_ASP.NET Core应用的错误处理[1]:三种呈现错误页面的方式

由于ASP.NET Core应用是一个同时处理多个请求的服务器应用&#xff0c;所以在处理某个请求过程中抛出的异常并不会导致整个应用的终止。出于安全方面的考量&#xff0c;为了避免敏感信息的外泄&#xff0c;客户端在默认的情况下并不会得到详细的出错信息&#xff0c;这无疑会在…

美国半导体十年计划中的NO.1,模拟硬件究竟有什么价值?

来源&#xff1a; 脑极体中国半导体行业在集体过冬&#xff0c;美国也未必没有紧迫感。前不久&#xff0c;美国半导体行业协会&#xff08;SIA&#xff09;和半导体研究公司&#xff08;SRC&#xff09;就联合发布了一份题为“半导体十年计划”的报告&#xff0c;希望美国政府能…

【编程开发】Python---列表

ERROR&#xff1a;错误 waring&#xff1a;警告&#xff0c;还没到犯错的地步 print(r\n) r"字符串"&#xff0c;字符串里的所有字符都不转义 str "abcdef" 如果想隔一个取出来&#xff0c;str[0::2] 深浅拷贝 列表的内存存放 Python修改的变量只是修改了…

processing python模式_详解python之多进程和进程池(Processing库)

环境:win7python2.7 一直想学习多进程或多线程,但之前只是单纯看一点基础知识还有简单的介绍,无法理解怎么去应用,直到前段时间看了github的一个爬虫项目涉及到多进程,多线程相关内容,一边看一边百度相关知识点,现在把一些相关知识点和一些应用写下来做个记录. 首先说下什么是进…

不确定性的价值

来源&#xff1a; 混沌巡洋舰推荐一篇万字长文 聪大脑的预测性编码讲起&#xff0c;区分三种不确定性&#xff0c;最终对我们如何应对这个充满不确定的时代&#xff0c;给出启示。愿读完后&#xff0c;你能够更全面客观的理解生活中的随机性。霍金斯是一位计算机科学家(后来成为…