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

(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})

友情链接:贪心算法

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Vue从入门到实战 Day08~Day10

智慧商城项目 1. 项目演示 目标&#xff1a;查看项目效果&#xff0c;明确功能模块 -> 完整的电商购物流程 2. 项目收获 目标&#xff1a;明确做完本项目&#xff0c;能够收获哪些内容 3. 创建项目 目标&#xff1a;基于VueCli自定义创建项目架子 4. 调整初始化目录 目…

基于springboot实现的校园博客系统

开发语言&#xff1a;Java 框架&#xff1a;springboot JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09; 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;eclipse/myeclipse/idea Maven…

工地升降机AI人数识别系统

工地升降机人数识别系统采用了AI神经网络和深度学习算法&#xff0c;工地升降机AI人数识别系统通过升降机内置的摄像头实时监测轿厢内的人员数量。通过图像处理和人脸识别算法&#xff0c;系统能够精确地识别升降机内的人数。一旦系统识别到人数达到或者超过设定的阈值&#xf…

QT--TCP网络通讯工具编写记录

QT–TCP网络通讯工具编写记录 文章目录 QT--TCP网络通讯工具编写记录前言演示如下&#xff1a;一、服务端项目文件&#xff1a;【1.1】server_tcp.h 服务端声明文件【1.2】thread_1.h 线程处理声明文件【1.3】main.cpp 执行源文件【1.4】server_tcp.cpp 服务端逻辑实现源文件【…

【MySQL进阶之路 | 基础篇】MySQL新特性 : 窗口函数

1. 前言 (1). MySQL8开始支持窗口函数. 其作用类似于在查询中对数据进行分组(GROUP BY)&#xff0c;不同的是&#xff0c;分组操作会把分组的结果聚合成一条记录. 而窗口函数是将结果置于每一条数据记录中. (2). 窗口函数还可以分为静态窗口函数和动态窗口函数. 静态窗口函数…

秋招突击——算法——模板题——区间DP(1)——加分二叉树

文章目录 题目描述思路分析实现代码分析总结 题目描述 思路分析 实现代码 不过我的代码写的真的不够简洁&#xff0c;逻辑不够清晰&#xff0c;后续多练练吧。 // 组合数问题 #include <iostream> #include <algorithm>using namespace std;const int N 35; int…

聚星宇学电商:现在开一家抖音网店真的好做吗

在数字经济的浪潮中&#xff0c;抖音以其强大的流量优势成为众多创业者眼中的“香饽饽”。然而&#xff0c;开一家抖音网店是否真的好做?这个问题值得我们深入探讨。 不可否认的是&#xff0c;抖音平台汇聚了海量的用户基础和丰富的社交属性&#xff0c;为商家提供了一个广阔的…

【Linux】Centos7安装RabbitMQ

【Linux】Centos7安装RabbitMQ 下载 从 rabbitmq 的 GitHub 仓库下载 https://github.com/rabbitmq/rabbitmq-server/releases rabbitmq 是 erlang 语言编写的&#xff0c;需要先安装 erlang https://github.com/rabbitmq/erlang-rpm/releases 安装 使用rz命令上传 erlang 和 …

【linux】yumvim工具理解使用

目录 Linux 软件包管理器 yum 关于 rzsz 注意事项 查看软件包 Linux开发工具 Linux编辑器-vim使用 vim的基本概念 vim的基本操作 vim正常模式命令集 vim末行模式命令集 简单vim配置 配置文件的位置 sudo提权 Linux 软件包管理器 yum 1.yum是什么&#xff1…

Jenkins动态slave

目录 所需环境 安装nfs 部署Jenkins 安装插件 ​编辑添加凭据 配置动态slave 连接kubernetes集群 ​编辑配置Jenkins地址 ​编辑配置Pod模板 ​编辑确认代理端口 创建任务测试 在当今软件开发生命周期中&#xff0c;持续集成/持续部署&#xff08;CI/CD&#xff09;已…

软件测试面试会问哪些问题?(二)

三、测试理论论 3.1 你们原来项目的测试流程是怎么样的 我们的测试流程主要有三个阶段&#xff1a;需求了解分析、测试准备、测试执行。 1、需求了解分析阶段 我们的 SE 会把需求文档给我们自己先去了解一到两天这样&#xff0c;之后我们会有一个需求澄清会议&#xff0c;我们会…

es数据备份和迁移Elasticsearch

Elasticsearch数据备份与恢复 前提 # 注意&#xff1a; 1.在进行本地备份时使用--type需要备份索引和数据&#xff08;mapping,data&#xff09; 2.在将数据备份到另外一台ES节点时需要比本地备份多备份一种数据类型&#xff08;analyzer,mapping,data,template&#xff09; …

计算机缺失ffmpeg.dll如何修复,五种详细的修复教程分享

当你在使用电脑过程中&#xff0c;突然遇到系统或软件弹出提示信息&#xff0c;告知“ffmpeg.dll文件丢失”怎么办&#xff1f;当电脑提示ffmpeg.dll丢失时&#xff0c;可能会导致一些应用程序无法正常运行或出现错误提示。下面我将介绍5种解决电脑提示ffmpeg.dll丢失的方法。 …

142.栈和队列:用栈实现队列(力扣)

题目描述 代码解决 class MyQueue { public:stack<int> stIn; // 输入栈&#xff0c;用于push操作stack<int> stOut; // 输出栈&#xff0c;用于pop和peek操作MyQueue() {}void push(int x) {stIn.push(x); // 将元素压入输入栈}int pop() {// 如果输出栈为空&…

16. Elasticsearch面试题汇总

Java全栈面试题汇总目录-CSDN博客 1. 什么是Elasticsearch? Elasticsearch是一个基于Lucene的搜索引擎。它提供了具有HTTP Web界面和无架构JSON文档的分布式&#xff0c;多租户能力的全文搜索引擎。 Elasticsearch是用Java开发的&#xff0c;根据Apache许可条款作为开源发布…

Docker镜像源自动测试镜像速度,并选择速度最快的镜像

国内执行如下代码 bash <(curl -sSL https://gitee.com/xjxjin/scripts/raw/main/check_docker_registry.sh)国外执行如下代码 bash <(curl -sSL https://github.com/xjxjin/scripts/raw/main/check_docker_registry.sh)如果有老铁有比较不错的镜像源&#xff0c;可以提…

局域网传文件怎么操作?轻松实现文件共享!

在现代的办公和生活中&#xff0c;局域网传文件已经成为一种非常常见和方便的方式&#xff0c;可以快速、安全地在局域网内进行文件传输。无需依赖互联网&#xff0c;局域网传文件可以帮助团队成员之间共享文件、备份数据、进行协作等。本文将介绍三种常见的方法&#xff0c;帮…

word-形状绘制、smartart、visio

一、人员架构图绘制 小技巧&#xff1a; 1、ctrlshift水平复制 2、点击图形&#xff0c;右键设置为默认形状 3、插入-形状-右键-锁定绘图模式&#xff0c;按esc退出状态 4、插入-形状-新建绘图画布&#xff0c;代替组合问题 画布中存在锚点&#xff0c;便于直线连接 二、s…

掌握一个面试小心机,就业离你只差这一步!

马上进6月份&#xff0c;大家是已经在工作岗位上了&#xff0c;还是正在面试呀&#xff01;不知道大家在面试过程中有没有遇到这样的问题&#xff0c;面试完几家公司之后进行总结&#xff0c;还是不知道自己为什么被pass掉&#xff0c;今天小编带大家搞清测试岗位面试的底层逻辑…

Centos7.9安装openldap和phpldapadmin

文章目录 一、背景二、正文2.1 安装openldap2.2 修改openldap配置2.3 安装phpldapadmin2.4 登录phpldapadmin界面 三、安装途中可能碰到的报错错误场景1&#xff1a;执行步骤“安装openldap”途中碰到的错误&#xff0c;即执行命令&#xff1a;systemctl start slapd报错错误场…