贪心算法(基础)

news2024/11/24 16:43:39

目录

一、什么是贪心?

(一)以教室调度问题为例

1. 问题

2. 具体做法如下

3. 因此将在这间教室上如下三堂课 

4. 结论

(二)贪心算法介绍  

1. 贪心算法一般解题步骤

二、最优装载问题

(一)问题 

(二)分析 

(三) 核心代码 

(四)完整代码

三、完全背包问题 

(一)问题 

(二)分析  

(三)举例  

(四)核心代码 

(五)完整代码

(六)物品类的完整代码


一、什么是贪心?

(一)以教室调度问题为例

1. 问题

  • 假设有如下课程表,你希望将尽可能多的课程安排在某一间教室上

  

2. 具体做法如下

  • 第一步:选出结束最早的课,它就是要在这间教室上的第一堂课
  • 第二步:接下来,必须选择第一堂课结束后才开始的课。同样,选择结束最早的课,这将是要在这间教室上的第二堂课 

3. 因此将在这间教室上如下三堂课 

 

4. 结论

  •  这道题就采取的贪心算法===>每步都采取最优的做法

(二)贪心算法介绍  

  • 贪心算法又称贪婪算法,是指在对问题求解时,总是做出当前看来最好的选择,它不是从整体上加以考虑,所做出的仅是在某种意义上的局部最优解。而局部的最优解叠加在一起便是该问题整体的最优解,或者近似最优解。

1. 贪心算法一般解题步骤

  • 将问题分解为若干个子问题
  • 找出合适的贪心策略
  • 求解每一个子问题的最优解
  • 将局部最优解堆叠成全局最优解

二、最优装载问题

(一)问题 

  • 有一艘海盗船,载重量为C,每一件古董的重量为w_{i},海盗们如何尽可能的把多数量的宝贝装上海盗船 ?

(二)分析 

  1. 当载重量为定值的时候,w_{i}越小时,可装载的古董数量n越大,只要依次选择最小重量的古董即可
  2. 把n个古董的重量从小到大(非递减)排序,然后根据贪心策略尽可能多地选出前i个古董,直到不能继续装为止

(三) 核心代码 

template<typename T1,typename T2,typename T3>
void Loading(T1 c, vector<T2>& w, vector<T3>& t, vector<bool>& v)
{
	//冒泡排序
	for (int i = w.size() - 1; i > 0; i--)//扫描次数
	{
		for (int j = 0; j < i; j++)
		{
			if (w[j] > w[j + 1])
			{
				swap(w[j], w[j + 1]);//交换物品重量
				swap(t[j], t[j + 1]);//交换物品的序号
			}
		}
	}

	for (int k = 0; w[k] <= c; k++)
	{
		v[k] = true;
		c = c - w[k];//船的剩余装载量
	}
}

(四)完整代码

#include<iostream>
#include<vector>
#include<stdbool.h>
using namespace std;
template<typename T1,typename T2,typename T3>
void Loading(T1 c, vector<T2>& w, vector<T3>& t, vector<bool>& v)
{
	//冒泡排序
	for (int i = w.size() - 1; i > 0; i--)//扫描次数
	{
		for (int j = 0; j < i; j++)
		{
			if (w[j] > w[j + 1])
			{
				swap(w[j], w[j + 1]);//交换物品重量
				swap(t[j], t[j + 1]);//交换物品的序号
			}
		}
	}

	for (int k = 0; w[k] <= c; k++)
	{
		v[k] = true;
		c = c - w[k];//船的剩余装载量
	}
}
int main()
{
	float c;//表示船的最大载重和物品个数
	int n;//物品个数
	cout << "请依次输入船的最大载重和物品个数:" << endl;
	cin >> c >> n;
	vector<float> w(n);//存放物品的重量
	vector<int> t(n);;//存放物品的下标
	vector<bool> v(n);//记录物品是否装入船中
	cout << "请依次输入物品重量:" << endl;
	for (int i = 0; i < n; i++)//初始化物品信息
	{
		cin >> w[i];
		t[i] = i;
		v[i] = false;
	}

	Loading(c,w,t,v);
	cout << "装入了:" << endl;
	for (int i = 0; i < w.size(); i++)//输出装入的物品
	{
		if (v[i] == true)
			cout << t[i] << "号物品," << "重量为:" << w[i] << endl;
	}
	return 0;
}
//测试数据
//30 8
//4 10.5 7.8 4.9 5.1 3.3 4.6 3.2
 

//结果
//装入了:
//7号物品,重量为:3.2
//5号物品,重量为:3.3
//0号物品,重量为:4
//6号物品,重量为:4.6
//3号物品,重量为:4.9
//4号物品,重量为:5.1

三、完全背包问题 

(一)问题 

  • 有n件物品,每件物品有一定的重量w和相应的价值v,背包的最大容量为bagW,一种物品只能拿一样(不可重复拿),物品可以分割,求解将哪些物品装入背包里物品价值总和最大?

(二)分析  

  • 依照贪心策略,每次选取单位重量价值最大的物品,也就是说每次选择性价比(价值/重量)最高的物品,如果达到运载重量bagW,那么一定能得到价值最大

(三)举例  

 背包最大容量为30,在依次选择物品2、10、6、3、5后,背包最大价值达到69,背包剩余容量为30-(2+5+8+9+5)=1,只能装8号物品的\frac{1}{4},此时背包最大价值为69+\frac{1}{4}\times 6=70.5

(四)核心代码 

void CompletePack(int _bagW,int n,struct goods*ps)
{
	double sum = 0;//背包总价值
	for (int i = 0;i<n; i++)
	{
		if (_bagW >ps[i].w)//背包容量大于物品重量
		{
			ps[i].c = 1;
			sum =sum+ ps[i].v;
			_bagW = _bagW - ps[i].w;//剩余背包容量
		}
		else//背包容量小于物品重量
		{
			ps[i].c = (double)_bagW / (double)ps[i].w;//装入物品的比例(必须要强制转换)
			sum =sum+ps[i].c *ps[i].v;
			break;
		}
	}
	cout << "背包最大价值:" << sum << endl;
}

(五)完整代码

#include<iostream>
#include<algorithm>
#include<iomanip>//setw的头文件
using namespace std;
#define MAX 100//物品数量最多为100
struct goods
{
	int n;//物品编号
	int w;//物品重量
	int v;//物品价值
	double p;//物品性价比
	double c;//记录装入物品的比例(如果物品完全放入背包,则c=1;不放入,c=0)
}g[MAX];

void Init(int n, struct goods*ps);//初始化物品信息
bool cmp(struct goods a,struct goods b);//比较
void CompletePack(int _bagW,int n,struct goods*ps);
void print(int n, struct goods* ps);//遍历

void Init(int n, struct goods*ps)//初始化物品信息
{
	cout << "请依次输入物品的重量和价值:" << endl;
	for (int i = 0; i < n; i++)
	{
		ps[i].n = i;//物品编号
		cin >>ps[i].w >> ps[i].v;//初始化物品重量和价值
		ps[i].p = (double)ps[i].v / (double)ps[i].w;//性价比
		ps[i].c = 0;//都没有放入背包
	}
}

bool cmp(struct goods a,struct goods b)//比较
{
	return a.p > b.p;//根据物品单位价值从大到小排序
}
void CompletePack(int _bagW,int n,struct goods*ps)
{
	double sum = 0;//背包总价值
	for (int i = 0;i<n; i++)
	{
		if (_bagW >ps[i].w)//背包容量大于物品重量
		{
			ps[i].c = 1;
			sum =sum+ ps[i].v;
			_bagW = _bagW - ps[i].w;//剩余背包容量
		}
		else//背包容量小于物品重量
		{
			ps[i].c = (double)_bagW / (double)ps[i].w;//装入物品的比例(必须要强制转换)
			sum =sum+ps[i].c *ps[i].v;
			break;
		}
	}
	cout << "背包最大价值:" << sum << endl;
}
void print(int n, struct goods* ps)
{
	for (int i = 0; i < n; i++)
	{
		if (ps[i].c != 0)
		{
			if (ps[i].c == 1)
				cout << "物品" << ps[i].n << setw(20) << "价值为:" << ps[i].v << endl;
			else
				cout << "物品" << ps[i].n << "装入了" << ps[i].c <<setw(8)<< "   价值为:" << ps[i].v << endl;
		}
	}
}

int main()
{
	int bagW, n;//背包最大容量和物品数量
	cout << "请依次输入物品重量和物品数量:" << endl;
	cin >> bagW >> n;
	Init(n,g);//初始化物品信息
	cout << endl<<endl ;
	sort(g, g + n, cmp);//排序
	CompletePack(bagW,n, g);
	print(n, g);
	return 0;
}

//测试数据
// 背包容量30  物品数量10
//4 3
//2 8
//9 18
//5 6
//5 8
//8 20
//5 5
//4 6
//5 7
//5 15

//结果
//背包最大价值:70.5
//物品1            价值为:8
//物品9            价值为:15
//物品5            价值为:20
//物品2            价值为:18
//物品4            价值为:8
//物品7装入了0.25   价值为:6

(六)物品类的完整代码

#include<iostream>
#include <iomanip>//setw的头文件
using namespace std;
#define MAX 20//物品数量最多为20
class goods
{
private:
	int number;//物品编号
	int weight;//物品重量
	double value;//物品价值
	double percentage;//物品性价比
	double choice;//记录装入物品的比例(如果物品完全放入背包,则choice=1;不放入,choice=0)
public:
	goods() { ; }
	goods(int _n,int _w, double _v, double _p, double _c)//构造函数
	{
		this->number = _n;
		this->weight = _w;
		this->value = _v;
		this->percentage = _p;
		this->choice = _c;
	}
	//~goods();//析构函数

	//获取私有成员
	int getn();//获取私有成员number
	int getw();//获取私有成员weight
	double getv();//获取私有成员value
	double getp();//获取私有成员percentage
	double getc();//获取私有成员choice

	//修改私有成员
	void setn(int _n);//修改私有成员的number
	void setw(int _w);
	void setv(double _v);
	void setp(double _p);
	void setc(double _c);
};

int goods::getn()
{
	return number;
}
int goods::getw()//获取私有成员weight
{
	return weight;
}
double goods::getv()
{
	return value;
}
double goods::getp()
{
	return percentage;
}
double goods::getc()
{
	return choice;
}

void goods::setn(int _n)
{
	number = _n;
}
void goods::setw(int _w)
{
	weight = _w;
}
void goods::setv(double _v)
{
	value = _v;
}
void goods::setp(double _p)
{
	percentage = _p;
}
void goods::setc(double _c)
{
	choice = _c;
}
int main()
{
	int bagW, n;//背包最大容量和物品数量
	cout << "请依次输入背包容量和物品数量:" << endl;
	cin >> bagW >> n;
	//goods *g=new goods[MAX];
	goods g[MAX];
	cout << "请依次输入物品重量和物品价值:" << endl;
	for (int i = 0; i < n; i++)
	{
		int _n,_w,_c;//物品编号,物品重量,物品是否放入了背包
		double _v, _p;//物品价值,物品性价比
		cin >> _w >> _v;
		_p = _v / _w;//性价比
		_n = i;//编号
		_c = 0;//是否放入了背包
		
		goods gg(_n, _w, _v, _p, _c);
		g[i] = gg;
	}
	

	for (int i = 0; i <= n - 1; i++)//简单选择排序(按照性价比从大到小)
	{
		double max = g[i].getp();
		int k = i;//保存最大性价比的物品下标
		for (int j = i; j < n; j++)
		{
			if (max < g[j].getp())
			{
				max = g[j].getp();
				k = j;
			}
		}
		swap(g[i], g[k]);
	}

	double sum = 0;//背包总价值
	for (int i = 0; i < n; i++)
	{
		if (bagW > g[i].getw())//背包容量大于物品重量
		{
			g[i].setc(1);//物品全部装入背包
			sum += g[i].getv();//背包价值增加
			bagW = bagW - g[i].getw();//剩余背包容量
		}
		else//背包容量大于物品重量
		{
			double x = double(bagW) / double(g[i].getw());
			g[i].setc(x) ;//装入物品的比例
			sum += g[i].getc() * g[i].getv();
			break;
		}
	}

	cout << "物品的最大价值为:" << sum << endl;
	for (int i = 0; i < n; i++)
	{
		if (g[i].getc() != 0)
		{
			if (g[i].getc() == 1)
				cout << "物品" << g[i].getn() << setw(20) << "价值为:" << g[i].getv() << endl;
			else
				cout << "物品" << g[i].getn() << "装入了" << g[i].getc() <<setw(8)<< "   价值为:" << g[i].getv() << endl;
		}
	}
	return 0;
}

//测试数据
//30 10
//4 3
//2 8
//9 18
//5 6
//5 8
//8 20
//5 5
//4 6
//5 7
//5 15

//结果
//物品的最大价值为:62.8
//物品2            价值为:8
//物品6            价值为:20
//物品3            价值为:18
//物品5            价值为:8
//物品8            价值为:6
//物品9装入了0.4   价值为:7

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

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

相关文章

智能驾驶 车牌检测和识别(四)《Android实现车牌检测和识别(可实时车牌识别)》

智能驾驶 车牌检测和识别&#xff08;四&#xff09;《Android实现车牌检测和识别&#xff08;可实时车牌识别&#xff09;》 目录 智能驾驶 车牌检测和识别&#xff08;四&#xff09;《Android实现车牌检测和识别&#xff08;可实时车牌识别&#xff09;》 1. 前言 2. 车…

SLAM数学知识回顾

文章目录1、三角函数2、向量运算&#xff08;1&#xff09;负向量&#xff08;2&#xff09;向量的模&#xff08;3&#xff09;标量与向量的运算&#xff08;4&#xff09;标准化向量&#xff08;5&#xff09;向量的加法和减法&#xff08;6&#xff09;距离公式&#xff08;…

三十七、Kubernetes1.25中数据存储第三篇

1、概述在前面已经提到&#xff0c;容器的生命周期可能很短&#xff0c;会被频繁地创建和销毁。那么容器在销毁时&#xff0c;保存在容器中的数据也会被清除。这种结果对用户来说&#xff0c;在某些情况下是不乐意看到的。为了持久化保存容器的数据&#xff0c;kubernetes引入了…

计算机视觉OpenCv学习系列:第十部分、实时人脸检测

第十部分、实时人脸检测第一节、实时人脸检测1.OpenCV人脸检测支持演化2.OpenCV DNN检测函数3.代码练习与测试学习参考第一节、实时人脸检测 1.OpenCV人脸检测支持演化 OpenCV4 DNN模块 DNN- 深度神经网络 来自另外一个开源项目tiny dnnOpenCV3.3正式发布最新版本OpenCV4.5.…

网络编程 之 epoll

epoll 参数设置 events设置 ev.events EPOLLIN | EPOLLET;epoll实现TCP通讯时&#xff0c;events通用设置如上&#xff0c;EPOLLIN代表可socket套接字可接收数据&#xff0c;EPOLLET代表边沿触发。在服务器端, 接受客户端连接的socket不能设置为EPOLLOUT&#xff0c;只设置E…

【5】【TypeScript】(TypeScript=Type+JavaScript)

Typescript 相比js特有 类型系统&#xff1b;对象的接口DOM操作时候需要进行类型断言上面三个实际是类型系统的三处体现枚举js中&#xff0c;-号可以强制转换为数值&#xff0c;ts不行 所有合法的js都是ts 1、安装 安装进度卡住可以用淘宝镜像 &#xff08;在后面加 --registr…

Spring Cloud Hystrix有什么作用?

在微服务架构中&#xff0c;通常会存在多个服务层调用的情况&#xff0c;如果基础服务出现故障可能会发生级联传递&#xff0c;导致整个服务链上的服务不可用&#xff0c;如图1所示。图1 服务故障的级联传递在图1中&#xff0c;A为服务提供者&#xff0c;B为A的服务调用者&…

反欺诈(羊毛盾)API有什么作用?

肯定很多企业、商家都遭受过羊毛党的侵入&#xff0c;比如恶意注册、刷单、领用的行为。羊毛党具体有哪些危害呢&#xff1f; 羊毛党的危害 虚假用户裂变&#xff1a;识别在游戏解锁、红包裂变、助力砍价、电商拼团等用户拉新活动中作弊行为。虚假登录注册&#xff1a;防止机…

Java基于springboot大学生宿舍寝室考勤人脸识别管理系统

简介 Java基于springboot开发的大学生寝室管理系统宿舍管理系统。学生可以查找寝室和室友信息&#xff0c;可以申请换寝室&#xff0c;申请维修&#xff0c;寝室长提交考勤信息&#xff08;宿管确认学生考勤信息&#xff09;&#xff0c;补签&#xff0c;查看寝室通报&#xf…

FPGA纯verilog代码实现图像缩放,两种插值算法任意尺寸缩放,提供3套工程源码

目录1、设计思路和架构2、纯verilog代码搭建&#xff0c;不带任何ip3、双线性插值和邻域插值算法4、vivado和matlab联合仿真及结果5、工程代码1&#xff1a;720P原始摄像头采集显示6、工程代码2&#xff1a;720P缩小到800x600P显示7、工程代码3&#xff1a;720P缩放大1920x1080…

结合FPGA和NVIDIA Jetson Orin NX 系统的视觉边缘计算机

边缘计算机采用NVIDIA Jetson Orin NX模块化系统和高带宽图像采集卡&#xff0c;用于实时图像采集计算和人工智能处理。虹科与一家专注于高速图像采集和处理的以色列科技公司Gidel合作&#xff0c;今天宣布新的NVIDIA Jetson Orin NX™ 16GB模块化系统(SoM)将被添加到Gidel的Fa…

Jmeter接口测试流程详解(中科软测认证中心)

Jmeter接口测试流程详解&#xff08;中科软测认证中心&#xff09; 目录&#xff1a;导读 1、jmeter简介 2、jmeter安装 3、设置jmeter的中文界面 4、jmeter主要元件 5、Jmeter元件的作用域和执行顺序 6、jmeter接口测试流程步骤 1、jmeter简介 Jmeter是由Apache公司开…

【数据架构系列-02】从《数据中台能力成熟度模型》的发布,聊聊火了的中台

热点之所以会“热起来”,是由于万众瞩目的那份炽烈,也是因为无数双“手”的奋力炒作。所以,要穿过那“缭绕烟雾”看到本质,便需要冷静的头脑。 2023年1月4日&#xff0c;信通院发布了《数据中台能力成熟度模型》框架&#xff0c;不由让我浮想联翩&#xff0c;之后是不是还会出现…

Python采集豆某影片并作词云图分析

前言 嗨喽~大家好呀&#xff0c;这里是魔王呐 ❤ ~! 目录前言环境使用:模块使用&#xff1a;爬虫基本思路:代码展示绘制词云图尾语 &#x1f49d;环境使用: Python 3.8 解释器 Pycharm 编辑器 模块使用&#xff1a; import parsel >>> pip install parsel import…

二叉树26:二叉树的最近公共祖先

主要是我自己刷题的一些记录过程。如果有错可以指出哦&#xff0c;大家一起进步。 转载代码随想录 原文链接&#xff1a; 代码随想录 leetcode链接&#xff1a;236. 二叉树的最近公共祖先 题目&#xff1a; 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 百度百科…

网络工程师备考9章

第九章:网络操作系统与应用服务器 9.1 考点分析 ​​​​​​​ 注:MCSE、RHCE基础:微软和红帽的系统工程师的内容都纳入到一章里;我们要学的服务器类型非常多,最重要的罗列下来,总结起来就是3D+I; 9.1.1 网络操作系统 9.2 安装过程 略 9.3 Windows Server 2008 R2 本…

创新科技引领清洁新标准,CEYEE希亦洗地机重新定义深度清洁

后疫情时代&#xff0c;随着人们健康意识的增强&#xff0c;家庭清洁卫生意识逐渐深入人心&#xff0c;大家对于清洁家电的选择也不再局限于基础功能&#xff0c;而是更注重智能化、健康化、便捷性、多功能等维度。创新型科技新消费品牌「CEYEE希亦」也由此应运而生&#xff0c…

SpringCloud-Eureka

1.Spring Cloud是什么&#xff1f; SpringCloud是一系列框架的有序集合。【包含了开发所需的其他的框架】 它利用SpringBoot的开发便利性&#xff0c;巧妙地简化了分布式系统基础设施的开发&#xff0c;如服务注册、服务发现、配置中心、消息总线、负载均衡、断…

如何安装python运行环境,想学python需要安装什么

这篇文章主要介绍了安装python程序后要进行什么设置&#xff0c;具有一定借鉴价值&#xff0c;需要的朋友可以参考下。希望大家阅读完这篇文章后大有收获&#xff0c;下面让小编带着大家一起了解一下。 1、使用python需要安装哪些软件 《Python 3.9.7软件》百度网盘资源免费下…

浅析DDOS攻击及防御

如今&#xff0c;信息技术的发展为人们带来了诸多便利&#xff0c;无论是个人社交行为&#xff0c;还是商业活动都离不开网络。但是&#xff0c;网络空间在创造机遇的同时&#xff0c;也带来了威胁&#xff0c;其中 DDOS 就是最具破坏力的攻击。经过这些年的不断发展&#xff0…