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

(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.rhkb.cn/news/329636.html

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

相关文章

彩色进度条(C语言版本)

.h文件 #include<stdio.h> #include<windows.h>#define NUM 101 #define LOAD_UP 50 #define LOAD_DOWN 60 #define SLEEP_SLOW 300 #define SLEEP_FAST 70 版本1&#xff1a;&#xff08;初始版&#xff09; //v1 #include "progress.h" int main() …

【云原生】Kubernetes基础命令合集

目录 引言 一、命令概述 &#xff08;一&#xff09;命令分类 &#xff08;二&#xff09;基本语法 二、查看基本信息 &#xff08;一&#xff09;环境指令 1.查看版本信息 2.查看资源对象简写 3.添加补全信息 4.查看日志 5.查看集群信息 &#xff08;二&#xff0…

vue打包部署到springboot,通过tomcat运行

tomcat默认端口 8080springboot端口 9132vue 端口 9131 框架 项目是基于SpringBootVue前后端分离的仓库管理系统 后端&#xff1a;SpringBoot MybatisPlus前端&#xff1a;Node.js Vue element-ui数据库&#xff1a;mysql 一. 打包Vue项目 cmd中输入命令 npm run build 后…

【施磊】C++语言基础提高:深入学习C++语言先要练好的内功

课程总目录 文章目录 一、进程的虚拟地址空间内存划分和布局二、函数的调用堆栈详细过程三、程序编译链接原理1. 编译过程2. 链接过程 一、进程的虚拟地址空间内存划分和布局 任何的编程语言 → \to → 产生两种东西&#xff1a;指令和数据 编译链接完成之后会产生一个可执行…

python将程序运行结果存入txt文本

//其实就是运行下面代码&#xff0c;然后下面代码会通过subprocess再去运行script.py&#xff08;我们的程序代码&#xff09;&#xff0c;然后把它写入oput.txt中。 import subprocess with open(oput.txt, w) as f:subprocess.run([python, script.py], stdoutf, stderrsu…

XX数字中台技术栈及能力

XX数字中台技术栈及能力 1 概述 XX数字中台面向数据开发者、数据管理者和数据应用者&#xff0c;提供数据汇聚、融合、治理、开发、挖掘、共享、可视化、智能化等能力&#xff0c;实现数据端到端的全生命周期管理&#xff0c;以共筑数字基础底座&#xff0c;共享数据服务能力…

酷开系统 | 酷开科技把握智慧先机 AI赋能家庭场景

智慧化是当今世界科技发展的前沿领域之一。现在的智慧化&#xff0c;也正在逐步成为我们日常生活的一部分。电视系统也进入了数字化时代&#xff0c;AI的应用正在不断扩展&#xff0c;其潜力似乎无穷无尽。 酷开科技深耕人工智能技术&#xff0c;在提升语音体验、强化智能家居…

目前流行的前端框架有哪些?

目前流行的前端框架有很多&#xff0c;它们可以帮助开发者快速构建高质量的前端应用程序。本文将介绍一些目前比较受欢迎的前端框架&#xff0c;并分析它们的优缺点。 React React 是一个由 Facebook 开发的开源前端JavaScript库&#xff0c;用于构建用户界面&#xff0c;尤其…

在vue中实现下载文件功能

实际操作为&#xff0c;在表格中 我们可以获取到文件的id&#xff0c;通过插槽就可以实现 <template #default"scope"><el-button type"text" click"handleDown(scope.row)"><span>下载</span></el-button> </…

计算机毕业设计 | springboot+vue汽车修理管理系统 汽修厂系统(附源码)

1&#xff0c;项目背景 在如今这个信息时代&#xff0c;“汽车维修管理系统” 这种维修方式已经为越来越多的人所接受。在这种背景之下&#xff0c;一个安全稳定并且强大的网络预约平台不可或缺&#xff0c;在这种成熟的市场需求的推动下&#xff0c;在先进的信息技术的支持下…

网络协议——Modbus-TCP

目录 1、简介 2、Modbus-TCP与Modbus-RTU的区别 3、消息格式 4、功能码01H 5、功能码02H 6、功能码03H 7、功能码04H 8、功能码05H 9、功能码06H 10、功能码0FH 11、功能码10H 1、简介 Modbus-TCP&#xff08;Modbus Transmission Control Protocol&#xff09;是一…

嵌入式学习——3——TCP-UDP 数据交互,握手,挥手

1、更新源 cd /etc/apt/ sudo cp sources.list sources.list.save 将原镜像备份 sudo vim sources.list 将原镜像修改成阿里源/清华源&#xff0c;如所述 阿里源 deb http://mirrors.aliyun.com/ubuntu/ bionic main …

【qt】QListWidget 组件

QListWidget 组件 一.QListWidget的用途二.界面设计三.QListWidget的添加1.界面添加2.代码添加 四.列表项的设置1.文本2.图标3.复选框4.列表大小 五.字体和图标的设置1.字体&#xff1a;2.图标&#xff1a; 六.设置显示模式1.图标2.列表 七.其他功能实现1.删除2.全选3.反选4.ad…

小微企业管理系统如何选择等保服务?

小微企业在选择等保&#xff08;信息安全等级保护&#xff09;服务时&#xff0c;应当考虑以下几个关键点以确保既能符合法规要求&#xff0c;又能在成本效益上做出合理决策&#xff1a; 了解等保需求&#xff1a;首先&#xff0c;小微企业需要了解自身的业务性质和信息系统的重…

30.包名的修改和新建后端模块

权限和第三方登录确实令人头疼,我们来学一点简单一点的。 另外,如果各位有属于自己的域名和ICP/IP备案,布置一个作业,自行实现第三方QQ登录。 我们所说的包名修改,是一次性修改ruoyi的全部包名,因为发现很多人有这样的需求,下载别人的代码,想要改成自己公司的包名,结…

深入Django项目实战与最佳实践

title: 深入Django项目实战与最佳实践 date: 2024/5/19 21:41:38 updated: 2024/5/19 21:41:38 categories: 后端开发 tags: Django 基础项目实战最佳实践数据库配置静态文件部署高级特性 第一章&#xff1a;Django项目架构与设计原则 Django框架概述 Django是一个高级的P…

上位机图像处理和嵌入式模块部署(mcu的按键输入)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 做技术的同学&#xff0c;大部分都会把精力放在技术本身&#xff0c;却忽视了学的东西有什么实际的用途。就拿gpio来说&#xff0c;一般我们点灯也…

递归的例子

例1&#xff1a;阶乘函数 #include<iostream> using namespace std; int f(int n) {if(n0)return 1;elsereturn f(n-1)*n; } int main() {int n;cin>>n;cout<<f(n);return 0; }例2&#xff1a;Fibonacci数列 无穷数列1&#xff0c;1&#xff0c;2&#xff0…

计算机-编程相关

在 Linux 中、一切都是文件、硬件设备是文件、管道是文件、网络套接字也是文件。 for https://juejin.cn/post/6844904103437582344 fork 进程的一些问题 fork 函数比较特殊、一次调用会返回两次。在父进程和子进程都会返回。 每个进程在内核中都是一个 taskstruct 结构、for…

Python函数进阶:四大高阶函数、匿名函数、枚举、拉链与递归详解

系列文章目录 Python数据类型&#xff1a;编程新手的必修课深入探索Python字符串&#xff1a;技巧、方法与实战Python 函数基础详解Python正则表达式详解&#xff1a;掌握文本匹配的魔法Python文件操作宝典&#xff1a;一步步教你玩转文件读写Python面向对象基础与魔法方法详解…