当前位置: 首页 > news >正文

ZOJ 1012 Mainframe

原题目链接

1012 主机

Ronald 先生在 ACM(数学计算代理)中负责主机的管理。代理会承接一些公司的数学计算任务,并在主机上完成任务后获得报酬。因此主机对 ACM 来说非常有价值。Ronald 先生需要安排主机上任务的运行顺序。当一个任务要运行时,他会检查任务的空闲资源,如果资源满足任务的要求,就把这些资源分配给任务,否则任务将暂停,直到有足够的资源。
在这里插入图片描述
因为刚开始不熟悉,所以他把所有的事情都搞乱了。久而久之,他便熟练了。并且,他总结了一套细则如下:

  1. 主机有M个CPU,可分配N个内存。
  2. 存在一个队列,用于存放等待执行的作业。您可以假设该队列足够大,可以容纳所有等待的作业。
  3. 一个作业 Ji 需要 Ai 个 CPU 和 Bi 个内存,在时间 Ti 到达队列。该作业需要在时间 Ui 之前完成。成功完成后,ACM 可获得 Vi( ) 作为奖励。如果提前完成,额外奖励为 W i ( ) 作为奖励。如果提前完成,额外奖励为 Wi( )作为奖励。如果提前完成,额外奖励为Wi()/小时。如果作业迟到,惩罚为 Xi( ) / 小时。例如,我们可以假设一个作业的价值为 10 )/小时。例如,我们可以假设一个作业的价值为 10 )/小时。例如,我们可以假设一个作业的价值为10,时间线为 8,惩罚为 2 / 小时。如果作业在时间 10 完成, A C M 将获得 10 − ( 10 − 8 ) ∗ 2 = 6 /小时。如果作业在时间 10 完成,ACM 将获得 10-(10-8)*2=6 /小时。如果作业在时间10完成,ACM将获得10(108)2=6
  4. 当作业开始执行时,所需的 CPU 和内存就被该作业占用,无法再分配给其他作业同时执行。作业完成后,这些资源将被释放。如果资源足够,则可以同时执行更多作业。
  5. 由于主机计算能力的共享,每个作业从开始执行到执行只需要一个小时就可以完成。你可以假设每个作业正好花费一个小时。
  6. 当没有作业需要执行时,主机将处于空闲状态,直到有作业到达作业队列。
  7. 如果有多个作业到达队列,则更有价值的作业将首先执行。你可以假设作业的价值总是不相等(ViVj)。
  8. 如果空闲的 CPU 或内存不能满足作业的需求,作业将暂停一小时,不占用任何资源。一小时后,将再次检查该作业的资源,而不考虑队列中的其他作业。如果需求再次不满足,作业将在接下来的一小时内保持暂停状态,队列中的其他作业将尝试分配资源。否则,作业将抢占所需的 CPU 和内存并开始执行。
  9. 当有多个作业被暂停时,先到达的作业将尝试首先被分配。

按照规则,Ronald先生可能把例行事务处理得很好。但现在,除了例行事务,ACM还要求他根据作业清单计算收益。给定时间线F,他必须计算已经执行或应该执行的作业。当然,根据作业Ji,如果Ui>F,作业没有执行,则不应计算在内;但那些已经执行或Ui<=F的作业应该计算在内。如果作业没有执行,它不会给ACM带来任何价值,这意味着只需要计算对时间线的惩罚。

确实,他的编程能力不够好,不喜欢手工计算。所以他对此感到不安。你能帮助他解决这个问题吗?

输入

输入包含若干个测试用例,每个用例描述了主机的资源和作业列表。每个测试用例以一行开头,其中包含一个整数 F,0 <= F <= 10000,时间行。下一行包含三个整数 M、N 和 L(M、N、L >= 0)。M 是主机中的 CPU 数量,N 是内存大小。L 表示作业列表中的作业数。最多会有 10000 个作业。

测试用例中接下来的L行描述了作业的信息。描述作业Ji的数据由7个整数Ai,Bi,Ti,Ui,Vi,Wi,Xi组成。Ai和Bi表示对CPU和内存的需求(Ai,Bi> = 0)。Ti和Ui表示作业到达的时间和时间表(0 <= Ti <= Ui)。Vi,Wi,Xi分别为作业的奖励,奖金和惩罚(Vi,Wi,Xi> = 0)。

输入文件以空测试用例(F=0)结尾。此用例不应被处理。

输出

你的程序必须根据作业列表计算主机的总收入。对于每个测试用例,打印用例编号、冒号和空格,然后打印收入。

每个测试用例后打印一个空白行。

注意:不计算尚未执行的作业,它们的时间线晚于 F。

示例输入

10
4 256 3
1 16 2 3 10 5 6
2 128 2 4 30 10 5
2 128 2 4 20 10 5
0

样本输入的输出

Case 1: 74

c++代码

#include<bits/stdc++.h>

using namespace std;

class work {
public:
    int A;
    int B;
    int T;
    int U;
    int V;
    int W;
    int X;
    bool select;
};

bool mycom(work a, work b) {
    if (a.T != b.T) return a.T < b.T;
    else return a.V > b.V;
}

int main() {
    int F, M, N, L, cont = 0;
    while (cin >> F) {
        if (F == 0) break;
        cont++;
        cin >> M >> N >> L;
        vector<work> works(L);
        for (int i = 0; i < L; i++) {
            cin >> works[i].A >> works[i].B >> works[i].T >> works[i].U >> works[i].V >> works[i].W >> works[i].X;
            works[i].select = false;
        }
        sort(works.begin(), works.end(), mycom);
        vector<work> current_work;
        int sum = 0;
        for (int i = 0; i <= F; i++) {
            for (work w : current_work) {
                if (i > w.U) sum += w.V - (i - w.U) * w.X;
                else if (i < w.U) sum += w.V + (w.U - i) * w.W;
                else sum += w.V;
                M += w.A;
                N += w.B;
            }
            current_work.clear();
            if (i == F) break;
            for (int j = 0; j < works.size(); j++) {
                if (i < works[j].T) break;
                if (works[j].select || works[j].A > M || works[j].B > N) continue;
                M -= works[j].A;
                N -= works[j].B;
                current_work.push_back(works[j]);
                works[j].select = true;
            }
        }
        for (int j = 0; j < works.size(); j++) {
            if (!works[j].select && works[j].U <= F) sum -= (F - works[j].U) * works[j].X;
        }
        cout << "Case " << cont << ": " << sum << endl << endl;
    }
    return 0;
}//by wqs

题目解析

这个题目并不是要你用贪心算法求出能获得的最大利润是多少,我一开始以为要我求这个,走了坑。

实际上题目意思是你按照题目给你的顺序来执行,最后的利润是多少。

我们不需要考虑怎样执行利润最大,只要按照顺序执行就行。

最早到达的最先执行,除非暂时执行不了(可能内存不够用)

同时到达的先执行价值大的。

如果最先到达的可以执行了(内存释放了),先执行最先到达的。

对于那些已经截止并且没有完成的工作,要计算罚金

解题步骤

给工作排序

最早到达的最先执行,除非暂时执行不了(可能内存不够用)

同时到达的先执行价值大的。

bool mycom(work a, work b) {
    if (a.T != b.T) return a.T < b.T;
    else return a.V > b.V;
}

sort(works.begin(), works.end(), mycom);
用一个数组存储正在执行的工作,1小时后结算
vector<work> current_work;
开始时间戳循环

对于时间戳0不需考虑结算执行的工作,因为还没有开始

对于时间戳F不需要考虑是否添加工作,因为已经结束。

否则既要结算执行的工作,又要引进新工作

for (int i = 0; i <= F; i++) {
    for (work w : current_work) {//结算工作
        if (i > w.U) sum += w.V - (i - w.U) * w.X;//惩罚
        else if (i < w.U) sum += w.V + (w.U - i) * w.W;//奖励
        else sum += w.V;
        M += w.A;//释放内存
        N += w.B;
    }
    current_work.clear();
    if (i == F) break;
    for (int j = 0; j < works.size(); j++) {//添加新工作
        if (i < works[j].T) break;//工作时间还没到
        if (works[j].select || works[j].A > M || works[j].B > N) continue;
        M -= works[j].A;
        N -= works[j].B;
        current_work.push_back(works[j]);//添加工作
        works[j].select = true;
    }
}
结算

对于那些已经截止并且没有完成的工作,要计算罚金

for (int j = 0; j < works.size(); j++) {
    if (!works[j].select && works[j].U <= F) sum -= (F - works[j].U) * works[j].X;
}

相关文章:

  • 关于XML映射器的基本问题
  • 【线性代数】2矩阵
  • DC-8靶机渗透测试全过程
  • Unity学习part2
  • python从入门到进去
  • [高等数学] 分部积分法
  • 计网-数据链路层
  • 【华为OD机考】华为OD笔试真题解析(10)--字符串重新排序
  • 使用 Python 爬虫和 FFmpeg 爬取 B 站高清视频
  • 【Python】错误异常
  • 【深度学习】计算机视觉(CV)-目标检测-DETR(DEtection TRansformer)—— 基于 Transformer 的端到端目标检测
  • DAY04 Object、Date类、DateFormat类、Calendar类、Math类、System类
  • 什么是计算机总线?
  • 【大模型】DeepSeek 高级提示词技巧使用详解
  • Android Studio报错:Could not get unknown property ‘kotlin_version‘
  • Kubernetes控制平面组件:etcd高可用集群搭建
  • c语言(初阶函数)完结
  • 函数防抖和节流
  • AI 语言模型发展史:统计方法、RNN 与 Transformer 的技术演进
  • Spring Boot01(注解、)---java八股
  • 铁肩担道义,历史鉴未来——中共中央政治局委员、外交部长王毅谈习近平主席对俄罗斯进行国事访问并出席纪念苏联伟大卫国战争胜利80周年庆典
  • 成就彼此,照亮世界:“中欧建交50周年论坛”在沪成功举行
  • 这座古村,藏着多少赣韵风华
  • 中俄弘扬正确二战史观:缅怀历史,重拾初心,阻止悲剧重演
  • 壹基金发布2024年度报告,公益项目惠及937万人次
  • 眉山“笑气”迷局:草莓熊瓶背后的隐秘与危机