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

news2024/9/21 5:50:18

(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;
    }
 
    // 设置起始节点的距离为0
    dist[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.coloradmin.cn/o/1685832.html

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

相关文章

怎么压缩pdf pdf在线压缩 pdf文件压缩大小

pdf文件无论在何种设备上打开&#xff0c;PDF文件都能保持其原始的布局和格式&#xff0c;这对于文档共享和打印非常重要。PDF不仅支持文本&#xff0c;还能嵌入图像、视频、音频以及动态链接等元素。PDF文件支持加密和密码保护&#xff0c;可以限制访问、编辑、复制或打印文档…

Dalle2学习

Dalle2 mini有GitHub库并且有网页可以直接测试

[图解]产品经理创新模式03封装领域逻辑

1 00:00:02,530 --> 00:00:06,840 第三个改进模式就是封装领域逻辑 2 00:00:06,840 --> 00:00:12,860 把人脑里面的封装的逻辑提炼出来 3 00:00:12,870 --> 00:00:13,740 放到电脑里面去 4 00:00:16,100 --> 00:00:21,440 比如说&#xff0c;销售员的&#xff0…

Zookeeper 安装教程和使用指南

一、Zookeeper介绍 ZooKeeper 是 Apache 软件基金会的一个开源项目&#xff0c;主要基于 Java 语言实现。 Apache ZooKeeper 是一个开源的分布式应用程序协调服务&#xff0c;提供可靠的数据管理通知、数据同步、命名服务、分布式配置服务、分布式协调等服务。 关键特性 分布…

《王者荣耀》4月狂揽2.34亿美元 单日流水1亿美元 全球销量第二

易采游戏网5月24日消息&#xff0c;在刚刚过去的四月&#xff0c;全球手游市场迎来了一场收益的盛宴&#xff0c;其中《王者荣耀》以其惊人的吸金能力&#xff0c;以2.34亿美元的月收入在全球手游排行榜上位列第二。4月5日&#xff0c;这款由腾讯游戏开发的多人在线战斗竞技游戏…

JS、Go、Rust 错误处理的不同 - JS 可以不用 Try/Catch 吗?

原文&#xff1a;Mateusz Piorowski - 2023.07.24 先来了解一下我的背景吧。我是一名软件开发人员&#xff0c;有大约十年的工作经验&#xff0c;最初使用 PHP&#xff0c;后来逐渐转向 JavaScript。 大约五年前&#xff0c;我开始使用 TypeScript&#xff0c;从那时起&#…

10、SpringBoot 源码分析 - 自动配置深度分析三

SpringBoot 源码分析 - 自动配置深度分析三 refresh和自动配置大致流程AutoConfigurationImportSelector的getAutoConfigurationEntry获取自动配置实体(重点)AutoConfigurationImportSelector的getCandidateConfigurations获取EnableAutoConfiguration类型的名字集合AutoConfig…

一个超级简单的Python UI库:NiceGUI

大家好&#xff0c;图形用户界面&#xff08;GUI&#xff09;的开发往往被看作是一项复杂且繁琐的任务。Python作为一门强大的编程语言&#xff0c;提供了许多优秀的库来帮助开发者实现这一目标。今天&#xff0c;我们将介绍一个名为NiceGUI的库&#xff0c;它能帮助你轻松构建…

基于Tensorflow+Keras的卷积神经网络(CNN)人脸识别

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 一、项目背景与意义 人脸识别是计算机视觉领域的一个重要研究方向&#xff0c;广泛应用于安全监控、身份验证、人机…

弘君资本股市资讯:深夜,利空突袭!美股大跳水!

昨夜&#xff0c;两大利空音讯突袭美股。 隔夜&#xff0c;最新披露的两则数据引发商场忧虑。其一是&#xff0c;美国5月Markit归纳PMI初值报54.4&#xff0c;创25个月新高&#xff0c;大幅高于预期的51.2&#xff0c;前值为51.3&#xff1b;其二是&#xff0c;在到5月18日的一…

05Django项目--前端公共文件和其他html文件的适配

对应视频链接点击直达 Django项目--前端公共文件和其他html文件的适配 对应视频链接点击直达前端页面准备Pubilc页面设置 OVER&#xff0c;不会有人不会吧不会的加Q1394006513结语 接着上一节 前端页面准备 为了方便大家更好的复制&#xff0c;我把整个项目及templates文件夹和…

docker如何拉取redis最新镜像并运行

要拉取Docker Hub上最新版本的Redis镜像&#xff0c;您可以使用以下命令&#xff1a; docker pull redis:latest 这里的latest标签会自动获取Redis镜像的最新版本。如果您希望指定一个确切的版本号&#xff0c;可以直接使用该版本号替换latest。例如&#xff0c;要拉取Redis版…

C++ (week5):Linux系统编程2:进程

文章目录 二、进程1.CPU的虚拟化2.进程命令(1)ps 3.进程的基本操作 (API)(1)获取进程的标识 (获得进程id)&#xff1a;getpid、getppid(2)创建进程&#xff1a;fork()(3)终止进程&#xff1a;exit()、_exit()、abort()、wait()、waitpid()①正常终止&#xff1a;exit()、_exit(…

Redis 源码学习记录:散列 (dict)

散列 Redis 源码版本&#xff1a;Redis-6.0.9&#xff0c;本篇文章的代码均在 dict.h / dict.c 文件中。 散列类型可以存储一组无需的键值对&#xff0c;他特别适用于存储一个对象数据。 字典 Redis 通常使用字典结构体存储用户散列数据。字典是 Redis 的重要数据结构。除了散…

AGM AG32 (MCU + FPGA)在音频处理上的应用案例

AGM AG32 (MCU FPGA)在音频处理&#xff0c;比如语音识别、降噪、声音增强等方面上的应用很多&#xff0c;结合AG32的特点&#xff0c;这里做一个简单的分享。 AGM AG32的架构是FPGA MCU&#xff0c;并且AG32与STM32的关键兼容&#xff0c;这个低成本的AG32器件&#xff0c;在…

MongoDB基础入门到深入(八)MongoDB整合SpringBoot、Chang Streams

文章目录 系列文章索引十五、MongoDB整合SpringBoot1、环境准备2、集合操作3、文档操作&#xff08;1&#xff09;相关注解&#xff08;2&#xff09;创建实体&#xff08;3&#xff09;添加文档&#xff08;4&#xff09;查询文档&#xff08;5&#xff09;更新文档&#xff0…

paligemma、Grounding-DINO-1.5简单无需标注无需训练直接可以使用的VLM图像到文本模型

1、paligemma 参考:https://github.com/google-research/big_vision/blob/main/big_vision/configs/proj/paligemma/README.md 模型架构: 文本与图像特征一起送入大模型 在线体验网址: https://huggingface.co/spaces/big-vision/paligemma 通过文字prompt既可与图片对话…

工行音视频服务平台建设与应用经验

近些年来&#xff0c;伴随着技术能力的积累突破&#xff0c;音视频服务开始蓬勃生长走进千家万户&#xff0c;使用远程视频通话、观看各类视频直播逐渐成为人们的日常&#xff0c;而金融服务作为社会生活的重要组成部分&#xff0c;自然需要积极拥抱应用新技术。 如今&#xff…

目标检测——无人机垃圾数据集

引言 亲爱的读者们&#xff0c;您是否在寻找某个特定的数据集&#xff0c;用于研究或项目实践&#xff1f;欢迎您在评论区留言&#xff0c;或者通过公众号私信告诉我&#xff0c;您想要的数据集的类型主题。小编会竭尽全力为您寻找&#xff0c;并在找到后第一时间与您分享。 …

【C++入门】—— C++入门 (下)_内联函数

前言&#xff1a;在了解完前面的C基础内容后&#xff0c;马上我们就要真正不如C的学习了&#xff0c;但在之前让我们最后了解最后一点点C入门知识&#xff01;来迟的520特别篇&#xff01; 本篇主要内容&#xff1a; 内联函数 auto关键字 范围for 指针空值nullptr C入门 1. 内联…