IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 贪心算法-会场安排与硬币找零问题 -> 正文阅读

[数据结构与算法]贪心算法-会场安排与硬币找零问题

一、会场安排

将会场按结束时间从早到晚排序后,将最早活动结束时间作为该会场最开始活动,第二项为开始时间晚于第一项,但是结束时间最早的一项,以此类推,直至遍历所有活动。

索引剩余活动,重复上述操作,直至无活动剩余。

重复次数即为至少所需会场数目。

#include<iostream>
#include<fstream>
using namespace std;

void sort(int data[], int num) {//将结束事件早的活动排在前面
	for (int i = 1;i < num;i = i + 2) {
		for (int j = 1;j < num - i - 1;j = j + 2) {
			if (data[j] > data[j + 2]) {
				int endTime = data[j];
				int startTime = data[j - 1];
				data[j] = data[j + 2];
				data[j - 1] = data[j + 1];
				data[j + 2] = endTime;
				data[j + 1] = startTime;
			}
		}
	}
}

//贪心算法寻找最少会场数目
int greedy(int data[], bool isArrange[], int num) {
	int count = 1;//设初始使用会场数目为1
	int endTime = data[1];//设置第一个活动的结束时间
	int i = 1;//设置当前指向活动,从第二项开始
	isArrange[0] = true;//将第一项活动状态改为已安排
	while (true) {
		bool flag = true;//用于判断是否全部活动都被安排
		for (int j = i * 2;j < num * 2;j = j + 2) {//从开始活动位置往后寻找
			if (isArrange[j / 2] == true) {//如果活动已被安排
				continue;
			}
			if (data[j] >= endTime) {//开始时间大于等于结束时间则可行
				isArrange[j / 2] = true;//设置为已安排
				endTime = data[j + 1];//更新结束时间
			}
		}
		for (;i < num;i++) {
			if (!isArrange[i]) {//当找到第一个未被安排时
				flag = false;
				endTime = data[2 * i + 1];//更新活动结束时间
				isArrange[i] = true;//更新安排
				count++;//需要的会场数增加
				break;
			}
		}
		if (flag == true) {
			break;
		}
	}
	return count;
}
int main() {
	ifstream ifs("input.txt", ios_base::binary);//输入文件位置
	ofstream ofs("output.txt", ios_base::binary);//输出文件位置
	int num = 0;//存储总活动数目
	int count = 0;//临时计数
	int* data = NULL;//存储活动区间
	bool* isArrange = NULL;//记录是否被安排
	if (!ifs) {
		return 1;
	}
	if (!ifs.eof()) {
		int  temp = 0;
		ifs >> temp;
		if (ifs.fail()) {
			ifs.clear();
			ifs.ignore(1);
		}
		num = temp;
	}
	data = new int[num * 2];
	isArrange = new bool[num];
	memset(isArrange, false, num * sizeof(bool));
	while (!ifs.eof()) {
		int temp = 0;
		ifs >> temp;
		if (ifs.fail()) {
			ifs.clear();
			ifs.ignore(1);
		}
		data[count] = temp;
		count++;
	}
	ifs.close();
	ifs.clear();
	sort(data, num * 2);
	count = greedy(data, isArrange, num);
	ofs << count;
	ofs.close();
	ofs.clear();
	return 0;
}

问题

如果使用链表来存储已排好序的活动数据,通过移除节点的方式可以让循环次数会大大降低,仅需要判断链表是否为空即可,而链表的第一项则是每一个会场的最开始的活动。

二、硬币找零

已知顾客与商家手中的硬币面值为

5分、1角、2角、5角、1元、2元(0.05,0.1,0.2,0.5,1,2)

商家手中硬币无限,而顾客手中硬币有限。

计算交易至少需要多少硬币数目,数目=顾客付的硬币数目+商家找回硬币数目

输入文件(input.txt)输出文件(output.txt)
顾客手中硬币应付金额

本次共需硬币数目

(顾客+商家)

0.050.10.20.512
2422100.95

2

顾客付出:1枚1元硬币

商家找回:1枚0.05元硬币

2420100.55

3

顾客付出:

1枚1元硬币+1枚0.05元硬币

商家找回:1枚0.5元硬币

依据贪心算法的思路,用最大的硬币面额以及最接近的硬币面额两个条件,去计算。同时注意数目是否超过。

根据硬币数目,在顾客方寻找最接近的单个硬币金额,找到后相减,保证为值中的最大负数,则再从商家方用相同方式寻找最接近的单个硬币金额,相加,保证为值中的最小正数,则再次回到顾客方,直到金额为0。?

#include<iostream>
#include<fstream>
using namespace std;

/*
数据格式
2 4 2 2 1 0 0.95
2 4 2 0 1 0 0.55
*/



int greedyCacl(int* data,float money) {
	float coin[] = { 0.05,0.1,0.2,0.5,1,2 };//对应金额
	int count = 0;//硬币数目
	bool flag = true;//true代表顾客,false代表商家
	int total = 0;//记录顾客手中的总钱数
	for (int i = 0;i < 6;i++) {
		total += coin[i] * data[i];
	}
	if (total < money) {//在硬币总金额小于应付款时,认为其无解
		return -1;//无解
	}
	else if (total == money) {//在硬币总金额等应付款时,全部给出
		for (int i = 0;i < 6;i++) {
			count += data[i];
		}
		return count;
	}

	//尽量用最大面额去支付
	//消去需要用多对枚硬币部分,留下金额使得至少有可用的硬币其面值超过该金额
	for (int i = 5;i >= 0;i--) {
		if (data[i] == 0) {
			continue;
		}
		int num = money / coin[i];//算得硬币数目
		if (num >= data[i]) {//大于或等于最大面额的硬币数目,则继续
			count = count + data[i];//记录硬币数目
			money = money - coin[i] * data[i];//求得剩余面额
			data[i] = 0;//清空
		}
		else {//如果当前面需要的数目大与应有数目,则记录不超过部分,并结束循环
			count = count + num;
			money = money - coin[i] * num;
			data[i] = data[i] - num;//减去已消耗部分
			break;
		}
	}
	//尽量用最接近但是超过或等于的硬币去支付
	while (abs(money) > 1e-6) {//当剩余金额为0时,则结束循环
		if (abs(money) < coin[0]) {//在金额小于最小面额时认为其无解
			return -1;//无解
		}
		float min = money;//记录最接近值
		int pos = 0;//记录位置
		if (flag) {//顾客付款
			for (int i = 5;i >= 0;i--) {//寻可行解
				if (data[i] == 0) {//为0则跳过
					continue;
				}
				float temp;//记录距离
				temp = money - coin[i];
				if (abs(temp) < 1e-6) {//等于0则结束
					pos = i;
					break;
				}
				else if (temp < -1e-6 && abs(temp) < min) {//距离需要为负,若比当前距离更近,则记录
					min = temp;
					pos = i;
				}
			}
			money = money - coin[pos];
			data[pos] = data[pos] - 1;
		}
		else {//商店找钱
			min = -min;//变为正数
			for (int i = 5;i >= 0;i--) {
				float temp;//记录距离
				temp = money + coin[i];
				if (abs(temp) < 1e-6) {//等于0则结束
					pos = i;
					break;
				}
				else if (temp > 1e-6 && temp < min) {//距离需要为正,若比当前距离更近,则记录
					min = temp;
					pos = i;
				}
			}
			money = money + coin[pos];
		}
		count = count + 1;
		if (money > 0) {
			flag = true;
		}
		else {
			flag = false;
		}
	}
	return count;
}

int main() {
	ifstream ifs("input.txt", ios_base::binary);//输入文件位置
	ofstream ofs("output.txt", ios_base::binary);//输出文件位置
	int count = 0;//用于临时计数
	int *data = new int[5];
	if (!ifs) {
		return 1;
	}
	//一行一行的计算数据
	while (!ifs.eof()) {

		float temp = 0;
		ifs >> temp;
		if (ifs.fail()) {
			ifs.clear();
			ifs.ignore(1);
		}
		if (count != 6) {//输入数据为每7个一行,由此断定输入完毕
			data[count] = temp;
			count++;
		}
		else {
			ofs << greedyCacl(data, temp) << endl;//输出
			count = 0;//清空
		}
	}
	ifs.close();
	ifs.clear();
	ofs.close();
	ofs.clear();
	return 0;
}

问题

数据过少,姑且在题目的基础上另外试了几组数据,但没有有效的数学理论证明它的正确性

同时其中的有些循环是多余的,仍有很大的改进空间

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-11-19 17:52:03  更:2021-11-19 17:53:15 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年1日历 -2025/1/9 2:10:53-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码