二.常见算法--贪心算法

(1)单源点最短路径问题

问题描述:

给定一个图,任取其中一个节点为固定的起点,求从起点到任意节点的最短路径距离。

例如:

思路与关键点:

以下代码中涉及到宏INT_MAX,存在于<limits.h>中。

首先,建立三个数组dist,S,W,prev分别用来存储从起始节点到任意节点的最短距离相对于s距离起点的最短路径节点集合存储要遍历的图的各条边的距离;用来存储各个节点的直接前驱节点。

3个主要的个功能函数。

(1)minDistance函数用来寻找V-S集合中的距离起点的最短距离,并返回该节点的下标。

(2)dijkstra函数用来寻找从起始节点到任意节点的最短路径长度。

思路是把节点分为两类,一类是没有放进S集合中的节点,一类是已经放进去的节点。那么,寻找从起始节点到节点v的最短路径就有两种可能的取值。

第一种是组成该最短路径的就是dist[v]。

第二种是新加入S集合的节点u可能会组成一个新的更短的路径,这时,要更新dist[v]。

(3)Traceback函数用来打印从源点到终点的路径。这个函数基于prev数组,该数组建立的核心原理是:每次更新dist数组,一定是因为s集合中增加了一个节点u,这个u一定是当前更新dist[v]的直接前驱节点。递归调用,不断找前一个前驱节点,就可以打印出完整路径了。

伪代码:

代码:

#include <iostream>
#include <limits.h>using namespace std;
#define V 6  // 节点的数量void Traceback(int v, int i, int prev[]);int minDistance(int dist[], int S[]);void printSolution(int dist[]);void dijkstra(int W[V][V], int src);int main() {int W[V][V] = {{0, 3, 2, 0, 0, 0},{0, 0, 0, 0, 1, 0},{0, 0, 0, 8, 4, 0},{0, 0, 0, 0, 0, 1},{0, 0, 0, 5, 0, 0},{0, 0, 0, 0, 0, 0}};dijkstra(W, 0);//起始节点为节点 0 return 0;}
// 找到距离数组中最小值的索引
int minDistance(int dist[], int S[]) {int min = INT_MAX, min_index;for (int j = 0; j < V; j++) {/*如果节点j没有包含在最短路径数组中,初始时,只要有路径,就更新最短路径数组的值。后面,每次进入循环都与当前的最短距离进行比较,更新。找到V(全部节点集合)-S(已找到的最短路径节点集合)中距离起点最短的路径的节点编号。 */ if (S[j] == 0 && dist[j] <= min) {min = dist[j];min_index = j;}}return min_index;
}// 打印最终的最短路径
void printSolution(int dist[]) {printf("节点\t最短距离\n");for (int i = 0; i < V; i++)printf("%d\t%d\n", i, dist[i]);
}// Dijkstra算法的实现
void dijkstra(int W[V][V], int src) {int dist[V];     // 存储从源节点到每个节点的最短距离int S[V];   // 记录节点是否已经包含在已找到的最短路径节点集合中int prev[V];// 初始化所有距离为无穷大,标记所有节点为未包含for (int i = 0; i < V; i++) {dist[i] = INT_MAX;S[i] = 0;}// 设置起始节点的距离为0dist[src] = 0;// 找到最短路径for (int count = 0; count < V - 1; count++) {// 选择距离最小的节点int u = minDistance(dist, S);// 标记节点为已包含S[u] = 1;// 更新相邻节点的距离for (int v = 0; v < V; v++) {/*如果该节点没有包含在最短路径数组中,有路径可直接到达该节点,并且有路径可达该节点,并且,从节点0到节点u的最短路径长度,与,从节点u到节点v的路径距离之和小于从节点0到该节点当前最短距离,则更新最短距离。 */ if (!S[v] &&W[u][v] && dist[u] != INT_MAX &&dist[u] +W[u][v] < dist[v]) {dist[v] = dist[u] + W[u][v];prev[v]=u;}}}// 打印最终的最短路径printSolution(dist);int v,i;printf("请输入源点及终点");cin>>v>>i;printf("从源点%d到终点%d的最短路径为:\n",v,i);Traceback(v,i,prev);
}
//输出最短路径 v源点,i终点,
void Traceback(int v, int i, int prev[])
{// 源点等于终点时,即找出全部路径if (v == i){cout << i;return;}Traceback(v, prev[i], prev);cout << "->" << i;
}

运行结果:

关键步骤证明:

时间复杂度与空间复杂度:

时间复杂度为0(n^{2}),空间复杂度为0(n^{2})。

(2)活动选择问题

问题描述:

假定有一个n个活动的集合S={a1,a2,……,an},这些活动使用同一个资源,而这个资源在某个时刻只能供一个活动使用。每个活动有一个开始时间si和一个结束时间fi,其中0<=si<fi<∞。如果被选中,任务ai发生在半开时间区间[si,fi)期间。如果两个活动ai和aj满足[si,fi)和[sj,fj)不重叠,则称他们是兼容的.也就是说,若si>=fj或sj>=fi,则ai和aj是兼容的。

在活动选择问题中,我们希望选出一个最大兼容活动集。

例子:

该活动序列的最大兼容活动集为1,4,8或1,4,9

思路与关键点:

按活动结束时间从小到大排序

每次选择的活动将作为是否与下一个活动兼容的判断依据。

伪代码:

代码:

#include<iostream>
#include<string.h>
using namespace std;
void Traceback(int Trace[],int n);
void sort(int n,int *s,int* f)
{int a,b,i,j;//冒泡排序,按结束时间从小到大排列活动 for(i=1;i<n;i++){for(j=1;j<n-i+1;j++){if(f[j]>f[j+1]){a=f[j];f[j]=f[j+1];f[j+1]=a;b=s[j];s[j]=s[j+1];s[j+1]=b;}}} 
}
int GreedySelect(int n,int s[],int f[],bool A[])
{int Trace[n];Trace[1]=1;A[1]=true;//第一个活动必然在最优解中 int j=1,count=1; //从第二个活动开始,寻找下一个兼容的活动 for(int i=2;i<=n;i++){if(s[i]>=f[j]){A[i]=true;j=i;//将已经选人的最后一个活动标号作为下一次比较兼容的参照 count++;Trace[count]=i;}else A[i]=false;} Traceback(Trace,count);return count;
}
//打印的活动序列是按照结束时间从小到大排好序的活动序列,而不是原来的活动序列 void Traceback(int Trace[],int n){printf("活动安排顺序为:");for(int i=1;i<=n;i++){cout<<"->"<<Trace[i];}cout<<endl;}
int main(){int n,s[50],f[50];bool A[50];memset(A,false,sizeof(A)); printf("请输入活动个数:\n"); cin>>n;//活动标号与数组下标保持一致,从1开始标号 for(int i=1;i<=n;i++){printf("请输入第%d个活动的开始时间和结束时间\n",i);cin>>s[i]>>f[i];printf("第%d个活动的开始时间是%d,结束时间是%d\n",i,s[i],f[i]);} sort(n,s,f);printf("最多相容活动数为:\n");cout<<GreedySelect(n,s,f,A)<<endl;return 0;
}

运行结果:

关键步骤证明:

时间复杂度与空间复杂度:

时间复杂度主要为排序花的时间为0(n^{2}),如果换成其他排序可以降低时间复杂度,空间复杂度为0(n)

(3)最小生成树--prim算法实现

问题描述:

给定一个图,求出其最小生成树

最小生成树定义
    对于一个带权(假定每条边上的权值均为大于零的实数)连通无向图G中的不同生成树,各树的边上的权值之和可能不同;图中所有生成树中具有边上的权值之和最小的树称为该图的最小生成树.

    按照生成树的定义,n个顶点的连通图的生成树有n个顶点和(n-1)条边.因此构造最小生成树的准则有三条:
(1) 必须只使用该图中的边来构造最小生成树;
(2) 必须使用且仅使用(n-1)条边来连接图中的n个顶点;
(3) 不能使用产生回路的边.

思路与关键点:

首先,这里有一个头文件<alogrithmn>,里面包含了丰富实用的函数,非常nice。这里使用到了其中的fill函数和min函数。分别用来填充数组和求最小值的。建立一个数组used,记录哪些没有进入最小生成树的集合,每次不断地将没有加入used中的距离加入used数组的节点 权值最小的节点加入used数组。 更新V轮mincost数组,得到最小生成树。

伪代码:

代码:

#include<iostream>
#include<algorithm>
#define MAX_V 100
#define INF 1000 
using namespace std;  int main()
{int V,E;int i,j,m,n;int cost[MAX_V][MAX_V];//存储每个节点之间的权值 int mincost[MAX_V];//记录那些已经进入最小生成树的节点之间的权值 bool used[MAX_V];//用于判断是否已经进入最小生成树,false表示否,true表示是 printf("请输入节点个数与边数\n"); cin>>V>>E;int Trace[V];fill(mincost,mincost+V+1,INF);//最小生成树一共有V个节点,V+1条边 fill(used,used+V,false);//一共有V个节点 //初始化cost[] for(i=0;i<V;i++){for(j=0;j<V;j++){if(i==j) cost[i][j]=0;//节点自己到自己权值为0 else cost[i][j]=INF; }}//向cost[]里面填充各个节点之间的权值 for(m=0;m<E;m++){printf("请输入两个端点以及它们之间边的权值\n");cin>>i>>j>>cost[i][j];cost[j][i]=cost[i][j];//无向图,中心对称 }mincost[0]=0; int res=0;//存储最终的最小生成树权值和 int count=0;/*遍历图,不断地将没有加入used中的距离加入used数组的节点权值最小的节点加入used数组。 
更新V轮mincost数组,得到最小生成树。 */while(true)//也可以写成for(int i=0;i<V;i++) {int v=V;for(m=0;m<V;m++){	if((!used[m])&&(mincost[m]<mincost[v]))v=m; }Trace[count]=v;count++;	if(v==V) break;Trace[count]=v;//最后一个跳出来了,没记录,要把最后一个节点加入 used[v]=true;res+=mincost[v];for(m=0;m<V;m++){/*取(新加入最小生成树的节点到其他节点的权值)和记录在mincost中的到其他节点的权值进行比较,取它们之间的最小值,来更新mincost数组*/ mincost[m]=min(mincost[m],cost[v][m]);  }}printf("最小生成树权值是:\n");cout<<res<<endl;printf("依次找到的节点是:\n");for(int i=0;i<V;i++){cout<<"->"<<Trace[i];}cout<<endl; 
}

运行结果:

输入上面单源点最短路径所示的图,运行结果如下

关键步骤证明:

视频证明

时间复杂度与空间复杂度:

时间复杂度与空间复杂度都是0(_n{2})

友情链接:贪心算法

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

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

相关文章

python+selenium - UI自动框架之封装查找元素

单一的元素定位方法不能满足所有元素的定位&#xff0c;可以根据每个元素的特点来找到合适的方法&#xff0c;可以参考下图的方法&#xff1a; elementFind.py from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_con…

MavLinK协议

由于在公司需要使用这个&#xff0c;我就写一个文章用于入门级别 简单介绍 MAVSDK是PX4开源团队贡献的基于mavlink通信协议的用于无人机应用开发的SDK&#xff0c;其可以部署在Windows、Linux、Android等多种平台&#xff0c;并且支持多种语言如c/c、python、Java等。 在官网…

python从0开始学习(九)

前言 上一篇文章我们介绍了python中的序列类型和元组类型&#xff0c;本篇文章将接着往下将。 1、字典类型 字典类型是根据一个信息查找另一个信息的方式所构成的“键值对”&#xff0c;它表示索引用的键和对应的值构成的成对关系。它是一个可变数据类型&#xff0c;也就是说它…

React中显示数据

SX 会让你把标签放到 JavaScript 中。而大括号会让你 “回到” JavaScript 中&#xff0c;这样你就可以从你的代码中嵌入一些变量并展示给用户。例如&#xff0c;这将显示 user.name&#xff1a; return (<h1>{user.name}</h1> ); 你还可以将 JSX 属性 “转义到 …

【Text2SQL 经典模型】TypeSQL

论文&#xff1a;TypeSQL: Knowledge-Based Type-Aware Neural Text-to-SQL Generation ⭐⭐⭐ Code: TypeSQL | GitHub 一、论文速读 本论文是在 SQLNet 网络上做的改进&#xff0c;其思路也是先预先构建一个 SQL sketch&#xff0c;然后再填充 slots 从而生成 SQL。 论文发…

2024 HGDD 荣耀开发者日·成都站

HGDD 荣耀开发者日成都站 活动时间&#xff1a;2024 年 5 月 27 日 活动地点&#xff1a;成都市双流区 LA CADIERE 蔚蓝湖滨城 期待与大家的见面&#xff01;

【oracle004】oracle内置函数手册总结(已更新)

1.熟悉、梳理、总结下oracle相关知识体系。 2.日常研发过程中使用较少&#xff0c;随着时间的推移&#xff0c;很快就忘得一干二净&#xff0c;所以梳理总结下&#xff0c;以备日常使用参考 3.欢迎批评指正&#xff0c;跪谢一键三连&#xff01; 总结源文件资源下载地址&#x…

Ubuntu 20/22 安装 Jenkins

1. 使用 apt 命令安装 Java Jenkins 作为一个 Java 应用程序&#xff0c;要求 Java 8 及更高版本&#xff0c;检查系统上是否安装了 Java。 sudo apt install -y openjdk-17-jre-headless安装完成后&#xff0c;再次验证 Java 是否已安装 java --version2. 通过官方存储库安…

APH-Archives of Public Health

文章目录 一、期刊简介二、征稿信息三、期刊表现四、投稿须知五、投稿咨询 一、期刊简介 Archives of Public Health是一份范围广泛的公共卫生杂志&#xff0c;致力于出版公共卫生领域所有可靠的科学。该杂志旨在更好地了解人群的健康。该杂志有助于公共卫生知识&#xff0c;加…

2024.5.20 学习记录

1、react 原理&#xff08;jsx的本质、事件机制原理、setState和batch Update、组件渲染更新和diff算法、fiber&#xff09; 2、代码随想录贪心刷题

ArcGIS10.X入门实战视频教程(arcgis入门到精通)

点击学习&#xff1a; ArcGIS10.X入门实战视频教程&#xff08;GIS思维&#xff09;https://edu.csdn.net/course/detail/4046?utm_sourceblog2edu 点击学习&#xff1a; ArcGIS10.X入门实战视频教程&#xff08;GIS思维&#xff09;https://edu.csdn.net/course/detail/404…

银河麒麟操作系统下使用QT连接TiDB数据库开发步骤

目标:实现项目软件+硬件都运行在国产化操作系统平台上。 方法:在虚拟机中安装麒麟系统V10Sp1+Qt5.14.2+MySql8.0+TiDB软件,编译MySql驱动,测试连接TiDB数据库项目。 步骤: 1、使用虚拟机软件VMWare安装银河麒麟操作系统。 2、在银河麒麟系统上安装QT5.14.2软件。 3、…

Web Server项目实战3-Web服务器简介及HTTP协议

Web Server&#xff08;网页服务器&#xff09; 一个 Web Server 就是一个服务器软件&#xff08;程序&#xff09;&#xff0c;或者是运行这个服务器软件的硬件&#xff08;计算机&#xff09;。其主要功能是通过 HTTP 协议与客户端&#xff08;通常是浏览器&#xff08;Brow…

[Cocos Creator 3.5赛车游戏]第5节 为汽车节点挂载自定义脚本

在前面的章节中您已经学会了如何创建一个汽车节点&#xff0c;这一章我们将会学习如何通过挂载自定义节点的方式让小车变得可控制&#xff0c;所以通过这一章的学习后&#xff0c;您将实现一个效果&#xff1a;开始运行后&#xff0c;小车每隔一帧就延y轴向上移动一段距离。在这…

顶顶通呼叫中心中间件-自动外呼输入分机号(比如隐私号)(mod_cti基于FreeSWITCH)

顶顶通呼叫中心中间件-自动外呼输入分机号(比如隐私号)(mod_cti基于FreeSWITCH) 比如有些人的号码是这样的就需要用上自动外呼输入分机号了 号码1&#xff1a;182XXXX8111-1234 号码2&#xff1a;182XXXX8222 如果号码是这样的就根据以下步骤配置 注意使用这个需要&#xff1a;…

Redis学习篇2:Redis在IEDA中的应用

本文继上文开始讲述了Redis在IDEA中如何应用以及集成进入spring开发环境&#xff0c;以及如何使用Redis客户端。上一个文章&#xff1a;Redis学习篇1&#xff1a;初识Redishttps://blog.csdn.net/jialuosi/article/details/139057088 一、Redis在java中的客户端 二、SpringDat…

树莓派 Raspberry Pi M.2 HAT+ 现已发售!原理图流出!

​Raspberry Pi M.2 HAT 使您能够将 M.2 M-key 外设&#xff08;如 NVMe 驱动器和人工智能加速器&#xff09;连接到 Raspberry Pi 5。它能够提供与这些外设之间的快数据传输&#xff08;高达 500 MB/s&#xff09;&#xff0c;现在就可以从树莓派的授权经销商网络购买&#xf…

c语言:strcmp

strcmp函数是用于比较两个字符串的库函数&#xff0c;其功能是根据ASCII值逐一对两个字符串进行比较。 语法&#xff1a;strcmp(str1, str2) 返回值&#xff1a; 如果str1等于str2&#xff0c;则返回0。 如果str1小于str2&#xff0c;则返回负数&#xff08;具体值取决于C…

注意力机制篇 | MSFE:即插即用的多尺度滑窗注意力(附源码实现)

前言:Hello大家好,我是小哥谈。多尺度滑窗注意力(Multi-Scale Sliding Window Attention,MSFE)是一种用于处理图像的深度学习模型。它通过引入多尺度特征提取和滑窗注意力机制来提高图像识别的准确性。在MSFE中,模型采用多尺度卷积神经网络来提取图像的特征,然后使用滑窗…

DELPHI通过WebService进行数据交互

WebService是一种可以跨语言和平台的数据交互模式&#xff0c;使用非常广泛&#xff0c;与JSon数据格式结合&#xff0c;更是当前非常流行的一种模式&#xff0c;本章针对DELPHI通过WebService进行数据的交互做一个相对简单例子应用。 本文使用的DELPHI 版本为&#xff1a;DEL…