文章目录
- 一、实验原理
- 1.1活动选择问题
- 1.2 贪心策略
- 二、实验要求
- 2,1 实现这个问题的贪心算法,并写出流程图或者伪代码
- 2.2 将每个 Wi 替换为 max{W1,W2……Wn}-Wi 运行算法、比较并分析结果。
- 总结
一、实验原理
提示:这里可以添加本文要记录的大概内容:
1.1活动选择问题
对几个互相竞争的活动进行调度,它们都要求以独占的方式使用某一公共资 源。而在同一时间内只有一个活动能使用这一资源。假设有一个需要使用某一资源的 n 个活动组成的集合 S={a1,a2,a3,…,an}。每个活动 ai 都有一个要求使用该资源的起始时间 si 和一个结束时间 fi,且 si <fi。如果选择了活动 i,则它在半开时间区间[si, fi)内占用资源。若区间[si, fi)与区间[sj, fj)不相交,则称活动 i 与活动 j 是兼容的。
活动选择问题就是要选择出一个由互不兼容的问题组成的最大子集合
1.2 贪心策略
动态规划是贪心算法的基础。
贪心算法即通过做一系列的选择来给出某一问题的最优解。对算法中的每一个决策点,做一个当时最佳的选择。贪心算法的使用条件:贪心选择性质和最优子结构是两个关键的特点。如果我们能够证明问题具有这些性质,那么就可以设计出它的一个贪心算法。
- 贪心选择性质:一个全局最优解可以通过局部最优(贪心)选择来达到。
- 最优子结构:对一个问题来说,如果它的一个最优解包含了其子问题的最优解,则称该问题具有最优子结构。
贪心算法的基本思路:
- 建立对问题精确描述的数学模型,包括定义最优解的模型;
- 将问题分解为一系列子问题,同时定义子问题的最优解结构;
- 应用贪心原则确定每个子问题的局部最优解,并根据最优解的模型,用
子问题的局部最优解堆叠出全局最优解
二、实验要求
实现一个任务调度问题(课本 P241):在单处理器上具有期限和惩罚的单位时间任务调度
- 实现这个问题的贪心算法,并写出流程图或者伪代码。
- 将每个 Wi 替换为 max{W1,W2……Wn}-Wi 运行算法、比较并分析结果
实例截图为:
2,1 实现这个问题的贪心算法,并写出流程图或者伪代码
代码如下:
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
using namespace std;
int main(){
int n;
cout << "请输入任务个数" << endl;
cin >> n;
vector<int> test(n,0);
vector<int> d(n,0);
vector<int> w(n,0);
vector<int> visited(n,0);
long result = 0;
cout << "请输入每个任务的截止时间" << endl;
for(int i = 0;i < n;i++){
cin >> d[i];
}
cout << "请输入每个任务的惩罚" << endl;
for(int i = 0;i < n;i++){
cin >> w[i];
}
for(int i = 0;i < n - 1;i++){
for(int j = 0;j < n - 1;j++){
if(w[j] < w[j+1]){
swap(d[j],d[j+1]);
swap(w[j],w[j+1]);
}
}
}
for(int i = 0;i < n;i++){
bool flag = false;
for(int j = d[i];j > 0;j--){
if(!visited[j - 1]){
visited[j - 1] = true;
flag = true;
break;
}
}
if(!flag){
cout << "放弃的任务截止时间为" << d[i] << "超市代价为" << w[i] << endl;
result += w[i];
}
}
cout << result << endl;
return 0;
}
如代码所示,主要思想就是根据惩罚时间的大小使用冒泡排序进行排序可以用其他排序方式进行优化,但由于后续选择任务调度的代码复杂度为O(n^2),因此不会提升整个代码的时间复杂度
,然后按顺序决定是否选择任务来调度,实现最小化延迟任务的惩罚之和。(每个任务都执行单位时间,因此看任务集中截止时间小于等于t的任务数是否小于等于t,判断是否可以调度该任务)。
输入书上的实例,得到该程序代码的输入输出截图如下图所示:
输入输出结果正确。
2.2 将每个 Wi 替换为 max{W1,W2……Wn}-Wi 运行算法、比较并分析结果。
代码如下即稍微改动一下即可
:
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
using namespace std;
int main(){
int n;
cout << "请输入任务个数" << endl;
cin >> n;
vector<int> test(n,0);
vector<int> d(n,0);
vector<int> w(n,0);
vector<int> visited(n,0);
long result = 0;
cout << "请输入每个任务的截止时间" << endl;
for(int i = 0;i < n;i++){
cin >> d[i];
}
cout << "请输入每个任务的惩罚" << endl;
for(int i = 0;i < n;i++){
cin >> w[i];
}
for(int i = 0;i < n - 1;i++){
for(int j = 0;j < n - 1;j++){
if(w[j] < w[j+1]){
swap(d[j],d[j+1]);
swap(w[j],w[j+1]);
}
}
}
for(int i = 0;i < n;i++){
bool flag = false;
for(int j = d[i];j > 0;j--){
if(!visited[j - 1]){
visited[j - 1] = true;
flag = true;
break;
}
}
if(!flag){
cout << "放弃的任务截止时间为" << d[i] << "超市代价为" << w[i] << endl;
result += w[i];
}
}
cout << result << endl;
return 0;
}
该程序的输入输出截图如图所示:
进行分析后,分析过程如图所示:
发现结果正确
以上两段代码,时间复杂度均为O(n^2)n为任务数
,空间复杂度为O(n)
总结
通过对任务调度问题使用贪心算法进行实现,加深了我对于贪心算法的理解和实践。