普里姆(prim)算法
普里姆算法是一种构造性算法。假设G = (V, E)是一个具有n个顶点的带权连通图,T = (U,TE)是最小生成树,其中U是T的顶点集,TE是T的边集,则由G构造从起始点v出法的最小生成树T的步骤如下:
(1). 从候选边中挑选权值最小的边加入TE,设该边在V—U中的顶点是k,将k加入U中。
(2). 考察当前V—U中的所有顶点j,修改侯选边,若(k,j)的权值小于原来和顶点关联的侯选边,则用(k,j)取代后者作为侯选边。
我们可以将定义理解为:将图的所有顶点分为两类,A类(保存已经查找过的顶点),B类(保存未查找过的顶点),从任一顶点开始,并将其从B类移至A类,然后开始寻找B类中(的顶点)到A类顶点之间权值最小的顶点,将其从B类中移至A类,重复上述操作,直至B类中没有顶点。所走过的顶点和边就是该连通图的最小生成树。
由此图为例:

初始状态
A类 = { }
B类 = { 0, 1, 2, 3, 4, 5, 6 }
假设从顶点2开始遍历
A类 = { 2 }
B类 = { 0, 1, 3, 4, 5, 6 }
遍历第一次后
A类 = {2, 3 }
B类 = { 0, 1, 4, 5, 6 }
遍历第二次后
A类 = { 1, 2, 3 }
B类 = { 0, 4, 5, 6 }
由此类推,直至B类中无顶点。
A类 = { 0, 1, 2, 3, 4, 5, 6 }
B类 = { }
图型讲解如下:
假设从顶点2开始遍历。

寻找B类到A类顶点之间权值最小的顶点(在现有的两条边寻找权值最小的边)。(上图为顶点3)将其添加至A类顶点中。

步骤同上。在现有的三条边(权值为12的边已经遍历过所以不计入)中寻找权值最小的边。(上图为顶点1)将其添加至A类中。大家注意在这里我们去掉了权值为18的边,这是因为从顶点1可以通过权值为14的边到达顶点6,从顶点3可以通过权值为18的边到达顶点6,根据定义我们要寻找顶点间权值最小的边,所以我们用权值为14的边替换权值为18的边。

步骤同上。在现有的三条边中寻找权值最小的边。(上图为顶点6)将其添加至A类。大家注意在这里增加顶点6,之后我们本应该可以获得一条从顶点6到顶点4权值为24的边,但是由于我们有从顶点3到顶点4的权值为22的边,所以根据定义,我们无需添加顶点6到顶点4权值为24的边

重复上述步骤。我们就可以通过prim算法得到最终的最小生成树。

看完了讲解,接下来让我们看看prim算法的代码实现吧!
\*
#define MAXV <最大顶点数>
#define INF 32767 //定义无穷大
typedef struct {
int no; //顶点的编号
InfoType info; //顶点的其他信息
}VertexType; //顶点的类型
typedef struct {
int edges[MAXV][MAXV]; //邻接矩阵数组
int n, e; //顶点数,边数
VertexType vexs[MAXV]; //存放顶点信息
}MGraph; //完整的图邻接矩阵类型
*\
void Prim(MGraph g,int v) { //传入一个邻接矩阵,和起始顶点
int lowcost[MAXV];
int closest[MAXV];
int min;
int i,j,k = 0;
for (i=0; i<g.n; i++) { //给lowcost[]和closest[]置初值
lowcost[i]=g.edges[v][i];
closest[i]=v;
}
lowcost[v] = 0;
for (i=1; i<g.n; i++) { //找出n-1个顶点
min=INF;
for (j=0; j<g.n; j++) { //在(V-U)中找出离U最近的顶点k
if (lowcost[j]!=0 && lowcost[j] < min) {
min=lowcost[j];
k=j; //k记录最近顶点的编号
}
}
printf(" 边(%d,%d)权为:%d\n", closest[k], k, min);
lowcost[k]=0; //标记k已经加入U
for (j=0; j<g.n; j++){ //对(V-U)中的顶点j进行调整
if (g.edges[k][j]<lowcost[j]) {
lowcost[j]=g.edges[k][j];
closest[j]=k; //修改数组lowcost和closest
}
}
}
}
初看代码相信很多人都是一头雾水,接下来就让我们对代码进行刨析。
我们先将上述的带权连通图转化成邻接矩阵为后续讲解做准备。
{ 0 , 28, INF, INF, INF, 10, INF }
{ 28, 0, 16, INF, INF, INF, 14 }
{ INF, 16, 0, 12, INF, INF, INF}
{ INF, INF, 12, 0, 22, INF, 18 }
{ INF, INF, INF, 22, 0, 25, 24 }
{ 10, INF, INF, INF, 25, 0, INF}
{ INF, 14, INF, 18, 24, INF, 0}
首先让我们一起看看这几句代码
for (i=0; i<g.n; i++) { //给lowcost[]和closest[]置初值
lowcost[i]=g.edges[v][i];
closest[i]=v;
}
这三行代码时我们整个算法的开始。那么这三行代码是在表达什么意思呢?
假设我们从顶底2开始,那么循环结束两个数组的值为
lowcost[] = { INF, 16, 0, 12, INF, INF, INF }
closest[] = { 2, 2, 2, 2, 2, 2, 2}
我们尝试着这样去理解一下。
lowcost数组中的每一个元素,我们将它理解为,A类元素到B类元素的最短距离。(无穷大表示目前还不能通过A类元素到达B类元素,0表示已经遍历过该顶点)
例如:
那么肯定有人有一个疑问为什么这里说的都是顶点2到其他的顶点的路径,那么请大家看看下面这句话。
closest数组中的每一个元素,我们将它理解为,lowcost数组中的边是哪一个顶点的邻边。或者也可以理解为A类元素暂且只有顶点为2的元素。
那么为什么这样去做,请大家跟着我一起继续向下看。
在分析了算法的开始之后,让我们看看接下来的几行代码
for (i=1; i<g.n; i++) { //循环n-1次 找出n-1个顶点
min=INF;
for (j=0; j<g.n; j++) { //在(V-U)中找出离U最近的顶点k
if (lowcost[j]!=0 && lowcost[j] < min) {
min=lowcost[j];
k=j; //k记录最近顶点的编号
}
}
printf(" 边(%d,%d)权为:%d\n", closest[k], k, min);
lowcost[k]=0; //标记k已经加入U
for (j=0; j<g.n; j++){ //对(V-U)中的顶点j进行调整
if (g.edges[k][j]<lowcost[j]) {
lowcost[j]=g.edges[k][j];
closest[j]=k; //修改数组lowcost和closest
}
}
}
接下来让我们来看看大的for循环中的第一个小循环。
for (j=0; j<g.n; j++) { //在(V-U)中找出离U最近的顶点k
if (lowcost[j]!=0 && lowcost[j] < min) {
min=lowcost[j];
k=j; //k记录最近顶点的编号
}
}
这个循环的意思为找出现有边中权值最小的边。并用k记录该边所连接的顶点。
那么在接下来输出(或其他操作)时我们就可以将这条边完整的输出出来。
printf(" 边(%d,%d)权为:%d\n", closest[k], k, min);
之后就到了整段代码的第二个核心。(那么什么是第一个核心,等我们一起看完整段代码后就会浮出水面)
lowcost[k]=0; //标记k已经加入U
for (j=0; j<g.n; j++){ //对(V-U)中的顶点j进行调整
if (g.edges[k][j]<lowcost[j]) {
lowcost[j]=g.edges[k][j];
closest[j]=k; //修改数组lowcost和closest
}
}
首先我们先将lowcost数组中最小边连接的顶点置0,表示该点已经加入A类。
然后大家注意这个if判断语句中的条件。
g.edges[k][j] < lowcost[j]
如果新顶点的邻边比现有待选边的权值小,就将其替换。目的还是为了确保下一次能找到最小边。
整段代码第一次执行结束后,让我们再来看看lowcost数组和closest的值。
lowcost[] = { INF, 16, 0, 0, 22, INF, 18 }
closest[] = { 2, 2, 2, 2, 3, 2, 3 }
这样下来我们不仅将新的顶点添加了进来(lowcost数组中索引为3的顶点值为0),还将新顶点的临边添加进来,最后还保证了待选边的最小特征。
好了,prim算法的讲解到此结束。
我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i
我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden
有时我需要处理键/值数据。我不喜欢使用数组,因为它们在大小上没有限制(很容易不小心添加超过2个项目,而且您最终需要稍后验证大小)。此外,0和1的索引变成了魔数(MagicNumber),并且在传达含义方面做得很差(“当我说0时,我的意思是head...”)。散列也不合适,因为可能会不小心添加额外的条目。我写了下面的类来解决这个问题:classPairattr_accessor:head,:taildefinitialize(h,t)@head,@tail=h,tendend它工作得很好并且解决了问题,但我很想知道:Ruby标准库是否已经带有这样一个类? 最佳
给定一个复杂的对象层次结构,幸运的是它不包含循环引用,我如何实现支持各种格式的序列化?我不是来讨论实际实现的。相反,我正在寻找可能会派上用场的设计模式提示。更准确地说:我正在使用Ruby,我想解析XML和JSON数据以构建复杂的对象层次结构。此外,应该可以将该层次结构序列化为JSON、XML和可能的HTML。我可以为此使用Builder模式吗?在任何提到的情况下,我都有某种结构化数据-无论是在内存中还是文本中-我想用它来构建其他东西。我认为将序列化逻辑与实际业务逻辑分开会很好,这样我以后就可以轻松支持多种XML格式。 最佳答案 我最
我正在尝试使用Curbgem执行以下POST以解析云curl-XPOST\-H"X-Parse-Application-Id:PARSE_APP_ID"\-H"X-Parse-REST-API-Key:PARSE_API_KEY"\-H"Content-Type:image/jpeg"\--data-binary'@myPicture.jpg'\https://api.parse.com/1/files/pic.jpg用这个:curl=Curl::Easy.new("https://api.parse.com/1/files/lion.jpg")curl.multipart_form_
无论您是想搭建桌面端、WEB端或者移动端APP应用,HOOPSPlatform组件都可以为您提供弹性的3D集成架构,同时,由工业领域3D技术专家组成的HOOPS技术团队也能为您提供技术支持服务。如果您的客户期望有一种在多个平台(桌面/WEB/APP,而且某些客户端是“瘦”客户端)快速、方便地将数据接入到3D应用系统的解决方案,并且当访问数据时,在各个平台上的性能和用户体验保持一致,HOOPSPlatform将帮助您完成。利用HOOPSPlatform,您可以开发在任何环境下的3D基础应用架构。HOOPSPlatform可以帮您打造3D创新型产品,HOOPSSDK包含的技术有:快速且准确的CAD
目录一.加解密算法数字签名对称加密DES(DataEncryptionStandard)3DES(TripleDES)AES(AdvancedEncryptionStandard)RSA加密法DSA(DigitalSignatureAlgorithm)ECC(EllipticCurvesCryptography)非对称加密签名与加密过程非对称加密的应用对称加密与非对称加密的结合二.数字证书图解一.加解密算法加密简单而言就是通过一种算法将明文信息转换成密文信息,信息的的接收方能够通过密钥对密文信息进行解密获得明文信息的过程。根据加解密的密钥是否相同,算法可以分为对称加密、非对称加密、对称加密和非
华为OD机试题本篇题目:明明的随机数题目输入描述输出描述:示例1输入输出说明代码编写思路最近更新的博客华为od2023|什么是华为od,od薪资待遇,od机试题清单华为OD机试真题大全,用Python解华为机试题|机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为o
本教程将在Unity3D中混合Optitrack与数据手套的数据流,在人体运动的基础上,添加双手手指部分的运动。双手手背的角度仍由Optitrack提供,数据手套提供双手手指的角度。 01 客户端软件分别安装MotiveBody与MotionVenus并校准人体与数据手套。MotiveBodyMotionVenus数据手套使用、校准流程参照:https://gitee.com/foheart_1/foheart-h1-data-summary.git02 数据转发打开MotiveBody软件的Streaming,开始向Unity3D广播数据;MotionVenus中设置->选项选择Unit