[CSP]计算资源调度器CCF认证真题

一、问题描述

【题目背景】

西西艾弗岛上兴建了一批数据中心,建设了云计算资源平台。小C是主管西西艾弗云开发的工程师。西西艾弗云中有大量的计算节点,每个计算节点都有唯一编号。

西西艾弗云分为多个可用区,每个计算节点位于一个特定的可用区。一个可用区中可以有多个计算节点。

西西艾弗云中运行的计算任务分为不同的应用,每个计算任务都有一个应用与之对应,一个应用中可能包括多个计算任务。每个计算任务由一个特定的计算节点执行,下文中计算任务“运行在某可用区上”意即“运行在某可用区的计算节点上”。

不同的计算任务对运行的计算节点的要求不尽相同。有的计算任务需要在指定可用区上运行,有的计算任务要和其它应用的计算任务在同一个可用区上运行,

还有的希望不要和某个应用的计算任务在同一个计算节点上运行。

对于一个计算任务,执行它的计算节点一旦选定便不再更改;在选定计算节点后,该任务对计算节点的要求就不再被考虑,即使新安排的计算任务使得此前已有的计算任务的要求被违反,也是合法的。

下图示意性地说明了可用区、计算节点、计算任务之间的关系,同时也说明了应用和计算任务的对应关系。

一开始,小C使用了电子表格程序来统计计算任务的分配情况。随着云上的计算节点和计算任务的不断增多,小C被这些奇怪的要求搞得焦头烂额,有的时候还弄错了安排,让客户很不满意。

小C找到你,希望你能为他提供一个程序,能够输入要运行的计算任务和对节点的要求,结合西西艾弗云的现有计算节点信息,计算出计算任务应该被安排在哪个计算节点上。

在这里插入图片描述

【问题描述】

计算任务对计算节点的要求十分复杂而且又不好描述,你对小C表示写程序这件事很为难。于是,小C进行了调研,将这些需求进行了归纳整理,形成了下面这三种标准需求。在提出需求时,必须从这三种标准需求中选取若干种,每种需求只能有一条。选取多种需求意味着要同时满足这些需求。

l 计算节点亲和性

计算任务必须在指定可用区上运行。

l 计算任务亲和性

计算任务必须和指定应用的计算任务在同一可用区上运行。

该要求对计算任务可以运行的可用区添加了限制。不考虑该任务本身,一个可用区若运行有指定应用的任务,则满足要求。

l 计算任务反亲和性

计算任务不能和指定应用的计算任务在同一个计算节点上运行。

该要求对计算任务可以运行的计算节点添加了限制。不考虑该任务本身,一个计算节点若运行有指定应用的任务,则不满足要求

当要执行的计算任务多起来,计算任务反亲和性的要求可能很难满足。因此在添加计算任务反亲和性要求时,还要指定这个要求是“必须满足”还是“尽量满足”。

小C要求你按照如下方法来分配计算节点:按照计算任务的启动顺序,根据要求,依次为每个计算任务选择计算节点。一旦选择了一个计算节点,就固定下来不再变动,

并且在此后的选择中,不再考虑这个计算任务的要求。对每个计算任务,选择计算节点的方法是:

  1. 过滤阶段

在这个阶段,先根据计算任务的要求,过滤出所有满足要求的计算节点。如果不存在这样的计算节点,并且指定了计算任务反亲和性要求,并且计算任务反亲和性要求是尽量满足的,

那么去掉计算任务反亲和性要求,再过滤一次。如果还不存在,就认为该计算任务的要求无法满足,该计算任务无法分配。

  1. 排序阶段

在这个阶段,将过滤后的计算节点按照这个方法排序:

1.选择此时运行计算任务数量最少的计算节点;

2.选择编号最小的计算节点。

【输入形式】

输入的第一行包含两个由空格分隔的正整数n和 m,分别表示计算节点的数目和可用区的数目。计算节点从1到n 编号,可用区从1到 m编号;

输入的第二行包含n个由空格分隔的正整数l1, l2,…, li ,…, ln,表示编号为 i 的计算节点位于编号为li的可用区。其中,0<
li <m;

输入的第三行包含一个正整数g,表示计算任务的组数;

接下来的g行,每行包含六个由空格分隔的整数fi、ai、nai、pai、paai、 paari,表示依次启动的一组计算任务的信息,其中:

fi:表示要接连启动fi个所属应用和要求相同的计算任务,其中 fi > 0;

ai:表示这fi个计算任务所属应用的编号,其中 0 < ai ≤ Amax ( Amax代表最大应用编号);

nai:表示计算节点亲和性要求,其中0<nai <m。当nai = 0时,表示没有计算节点亲和性要求,

否则表示要运行在编号为 nai的可用区内的计算节点上;

pai:表示计算任务亲和性要求,其中 0 ≤ pai ≤ Amax。当 pai =0时,表示没有计算任务亲和性要求,否则表示必须和编号为
pai的应用的计算任务在同一个可用区运行;

paai:表示计算任务反亲和性要求,其中 0≤ paai≤ Amax。当 paai
=0时,表示没有计算任务反亲和性要求,否则表示不能和编号为paai的应用的计算任务在同一个计算节点上运行;

paari:表示计算任务亲和性要求是必须满足还是尽量满足,当 paai=0时,paari也一定为0:否则 paari =1表示“必须满足”,
paari=0表示“尽量满足”。

计算任务按组输入实际上是一种简化的记法,启动一组( fi , ai , nai, pai, paai, paari)和连续启动fi组( 1
, ai , nai, pai, paai, paari)并无不同。

【输出形式】

输出 g行,每行有fi个整数,由空格分隔,分别表示每个计算任务被分配的计算节点的情况。若该计算任务没有被分配,则输出0; 否则输出被分配的计算节点的编号。

【样例输入】

10 4

1 1 1 1 1 2 2 2 2 2

6

2 1 4 1 2 1

6 1 1 0 1 1

1 2 2 0 0 0

6 1 2 0 2 1

5 2 2 0 1 0

11 3 0 1 3 0

【样例输出】

0 0

1 2 3 4 5 0

6

7 8 9 10 7 8

6 6 6 6 6

1 2 3 4 5 9 10 7 8 6 1

【样例说明】

本输入中声明了十个计算节点,前五个位于可用区 1,后五个位于可用区2。可用区3和4 不包含任何计算节点。

对于第一组计算任务,由于它们声明了计算节点亲和性要求,但要求的可用区编号是4,该可用区不包含计算节点,因此都不能满足。

对于第二组计算任务,要在可用区1中启动6份应用Ⅰ的任务,并且要求了计算任务反亲和性。因此,前五份任务分别被安排在前五个节点上。对于第六份任务,由于它必须运行于可用区
1,所以能够安排的范围仅限于前五个节点。但是它还指定了强制的计算任务反亲和性,前五个节点上已经启动了属于应用1的计算任务,因此没有能够运行它的节点。

对于第三组计算任务,要在可用区2中启动1份应用2的任务,直接将其分配给节点6。

对于第四组计算任务,要在可用区2中启动6份应用1的任务,并且要求了计算任务反亲和性,不能和应用﹖的计算任务分配在同一个节点上。因此,节点6不能用于分配,这六份任务只能分配在节点7~10上。按照题意,选取运行任务数最少的和编号最小的,因此依次分配7、8、9、10、7、8。

对于第五组计算任务,要在可用区2中启动5份应用2的任务,并且要求了尽量满足的计算任务反亲和性,不能和应用Ⅰ的计算任务分配在同一个节点上。此时,可用区2中的节点6上没有应用1的计算任务,因此这5份计算任务都会被分配到这个节点上。

对于第六组计算任务,要启动11份应用3的任务,并且要求了尽量满足的计算任务反亲和性,不能和应用3的其它计算任务分配在同一个节点上,同时要求和应用Ⅰ的计算任务位于同一个可用区。应用1位于两个可用区,因此全部10个节点都可以用于分配。对于前10份任务,按照题意,依次选取运行的任务数最少且编号最小的节点进行分配。对于第11份任务,由于所有的节点上都运行有应用3的任务,因此没有节点符合它的反亲和性要求。又因为反亲和性要求是尽量满足的,因此可以忽略这一要求,将它安排在节点1上。

二、代码实现

只筛选一次,把所有可用节点放堆中,每个字任务取堆顶节点

#include<iostream>
#include<cstdio>
#include<map>
#include<string>
#include<queue>
#include<vector>
using namespace std;

struct Node 
{   //存放计算节点的结构体
    int num;    
    int count;   
    int from;  
    map<int, bool> book; 
    bool operator < (const Node& a)const {
        if (count != a.count) return count > a.count;
        else return num > a.num;
    }
}nds[1006];

map<int, bool> quyu[1006]; 
int n, m, g;


priority_queue<Node> xuanze(int& a, int& na, int& pa, int ppa, int& paar) {
    //亲和性
    vector<Node> c1;
    if (na) 
    {
        for (int j = 1; j <= n; j++) {
            if (nds[j].from == na) c1.push_back(nds[j]);
        }
    }
    else {
        for (int j = 1; j <= n; j++) c1.push_back(nds[j]);
    }
    //任务亲和性
    vector<Node> c2;
    if (pa) {
        for (int j = 0; j < c1.size(); j++) {
            if (quyu[c1[j].from][pa]) c2.push_back(c1[j]);
        }
    }
    else c2 = c1;
    //反亲和性
    vector<Node> c3;
    if (ppa) {
        for (int j = 0; j < c2.size(); j++) {
            if (!c2[j].book[ppa]) c3.push_back(c2[j]);
        }
    }
    else c3 = c2;
    
    priority_queue<Node> final;
    for (int j = 0; j < c3.size(); j++) final.push(c3[j]);
 
    return final;
}


int ans(int tf, priority_queue<Node> & final, int& a, int paa)
{
    while (tf && !final.empty()) 
    {

        Node temp = final.top();
        final.pop();
        cout << temp.num << ' ';
      
        nds[temp.num].count++;
        nds[temp.num].book[a] = true;
        quyu[temp.from][a] = true;
     
        if (a != paa) temp.count++, final.push(temp);
        tf--;
    }
    return tf;
}

int main()
{
    cin >> n >> m;
    for (int i = 1; i <= n; i++) nds[i].num = i; 
    for (int i = 1; i <= n; i++)
    {
        int temp;
        cin >> temp;
        nds[i].from = temp;
    }
    cin >> g;
    while (g--)
    {
        int f, a, na, pa, paa, paar;
        cin >> f >> a >> na >> pa >> paa >> paar;
        priority_queue<Node> final = xuanze(a, na, pa, paa, paar);
        int tf = ans(f, final, a, paa);
        if (tf && !paar) 
        {//如果任务没分配完并且反亲和性不是必须的,那么再过滤一次,再打印一次
            final = xuanze(a, na, pa, 0, paar);
            tf = ans(tf, final, a, 0);
        }
        while (tf--) cout << 0 << ' ';
        cout << endl;
    }
    
    return 0;
}

在这里插入图片描述

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AF帆_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值