202203 CSP认证 | 出行计划 计算资源调度器

文章讲述了作者在编程中遇到关于差分数组范围调整的问题,并介绍了如何在资源调度问题中考虑节点亲和性和反亲和性。作者分享了解决算法和部分代码片段,强调了理解和正确处理边界条件的重要性。

出行计划
算是做了几次了,这次是比较快的反应到了是要用到差分数组
有一个地方改了很久的BUG就是在代码的18行。最开始我将N赋值为2e5 + 10,但是这里忽略了我用数组的范围,此时q的范围是2e5但是k的范围是1e5。在访问数组的时候我是q + k所以此时应该将数组开到3e5的范围上去,否则一直WA
在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
const int N = 3e5 + 10;
int Time[N];  //一个差分数组
int main()
{
    ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    int n, m, k; cin >> n >> m >> k;
    int MAX = 0;
    while(n --){
        int t, c; cin >> t >> c;
        if(t > MAX) MAX = t;
        int left = max(1, t - c + 1), right = t;   //找到区间的左右端点,在该区间的生效核酸都是合格的
        Time[left] ++;
        Time[right + 1] --;
    }

    for(int i = 1;i <= 3e5;i ++){
        Time[i] += Time[i - 1];
    }

    while(m --){
        int q; cin >> q;
        cout << Time[q + k] << endl;
    }
    return 0;
}

计算资源调度器
还好还好,这个题目读懂题意然后做就好了,难度不高

两个亲和性都是对可用区域做出限制,而反亲和性是对计算节点做出限制。
先分别计算可用区域有哪些以及非法的计算节点有哪些(两个都很简单),然后再遍历在合法可用区域上的所有计算节点,如果在非法节点里面就continue,否则就加入到备选答案里面去。
如果此时ans,也就是备选答案为空,且paar = 0。则删去非法节点的限制,将所有合法可用区中的节点全部加入到备选答案里面去。最后就是搜索了。

acwing上面TLE了…但是平台上过了…BTW既然这样我就不管了
在这里插入图片描述

满分代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
struct task{  //计算任务
    ll app;    //运行在哪个应用上
    int area;  //运行在哪个可用区上
    int node;  //运行在哪个节点上
};
const int N = 1010; //计算节点和分区的最大数目
const int INF = 0x3f3f3f3f;
int n, m;
int node_count[N];  //每个计算节点运行的任务数量
int node_zone[N];   //为了读取开的一个数组
unordered_map<ll, vector<task> > AppTask;  //app上运行的计算任务
unordered_map<int, vector<int> > Zone;   //每个可用区上有哪些计算节点


//对可用区域进行限制,找到所有合法的可用区
unordered_set<int> cal_pa(int na, ll pa)
{
    unordered_set<int> avai_zone;
    if(!AppTask.count(pa)){    //当前应用没有运行任何的计算任务
        return avai_zone;
    }
    vector<task> vec = AppTask[pa];  //找到当前应用下运行的所有计算任务
    for(int i = 0;i < vec.size();i ++){
        if(na){  //如果有节点亲和性
            if(vec[i].area == na){   //当前应用有计算任务运行在该可用区域上,此时满足两个条件
                avai_zone.insert(na);
                break;
            }
        }else{
            avai_zone.insert(vec[i].area); //所有计算任务的可用区都合法
        }
    }
    return avai_zone;
}
//找到所有的不合法节点
unordered_set<int> cal_paa(ll paa)
{
    unordered_set<int> unavai_node;
    if(AppTask.count(paa)){
        vector<task> vec = AppTask[paa];
        for(int i = 0;i < vec.size();i ++){  //遍历该应用上的每一个计算任务
            unavai_node.insert(vec[i].node);   //每一个任务的计算节点都为不合法节点
        }
    }
    return unavai_node;
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin >> n >> m;
    for(int i = 1;i <= n;i ++){
        int x; cin >> x;
        Zone[x].push_back(i);
        node_zone[i] = x;
    }

    int f, na, paar, g;
    ll a, pa, paa;
    task temp;
    set<int> ans;  //因为需要节点的编号最小,这里用set而非unordered_set

    cin >> g;
    while(g --){
        cin >> f >> a >> na >> pa >> paa >> paar;
        bool flag = false; //对可用区是否有要求
        if(na || pa) flag = true;  //对可用区有要求
        while(f --){  //将每个任务独立处理-->主要是针对若paa = a的情况
            unordered_set<int> avai_zone;
            unordered_set<int> unavai_node;
            temp.app = a;

            if(pa) avai_zone = cal_pa(na, pa); //如果对pa&na || only pa有要求
            else if(na) avai_zone.insert(na);  //如果只对na有要求

            if(!avai_zone.size() && flag) {
                cout << "0 ";
                continue;
            }  //没有可用区满足要求,此时必然也没有节点满足要求
            if(paa)  unavai_node = cal_paa(paa);


            if(!flag){  //对可用区没有要求
                for(int i = 1;i <= n;i ++){
                    if(unavai_node.count(i)) continue;  //只要不是非法计算节点都可
                    ans.insert(i);
                }
            }
            else{
                for(auto az : avai_zone){  //遍历每一个可用区域
                    for(auto node : Zone[az]){  //遍历该可用区中的每一个节点
                        if(unavai_node.count(node)) continue;
                        ans.insert(node);  //为合法的可用节点
                    }
                }
            }

            if(!ans.size() && !paar){  //去掉反亲和性的要求
                for(auto az : avai_zone){
                    for(auto node : Zone[az]){
                        ans.insert(node);
                    }
                }
            }
            if(!ans.size()) {cout << "0 "; continue;}

            //此时ans中留下来的都为筛选下来的合法节点
            int MAX = INF, index;
            for(auto node : ans){
                if(node_count[node] < MAX){
                    MAX = node_count[node];
                    index = node;
                }
            }
            cout << index << ' ';
            temp.node = index;
            temp.area = node_zone[index];
            AppTask[a].push_back(temp);
            node_count[index] ++;
            ans.clear();

        }
        cout << "\n";
    }
    return 0;
}

CCF(China Computer Federation)CSP(Certified Student Programmer,中国计算机学会认证程序设计)主要是针对青少年和大学生的一门计算机科学竞赛,其中涉及到的计算资源调度问题通常是在算法设计和模拟环境中,比如处理任务分配、并发控制等场景。 关于编写一个简单的计算资源调度器,这里举一个Python的例子,假设我们有任务队列和一个固定数量的处理器: ```python import queue class ResourceScheduler: def __init__(self, num_processors): self.processors = [None] * num_processors self.task_queue = queue.Queue() def add_task(self, task): self.task_queue.put(task) def schedule_tasks(self): while not self.task_queue.empty(): if all(processor is None for processor in self.processors): # 如果所有处理器都空闲,选择一个任务并分配给第一个处理器 current_processor = next((i for i, processor in enumerate(self.processors) if processor is None), None) if current_processor is not None: self.processors[current_processor] = self.task_queue.get() else: # 否则,找到第一个忙碌处理器,并将它的任务移除后分配给下一个处理器 for i, processor in enumerate(self.processors): if processor is not None: completed_task = processor self.processors[i] = None break self.task_queue.put(completed_task) # 使用示例 scheduler = ResourceScheduler(2) scheduler.add_task("Task1") scheduler.add_task("Task2") scheduler.schedule_tasks() ``` 这只是一个基础的简单例子,实际的资源调度器可能会更复杂,考虑到优先级、依赖关系等因素,并使用更高效的数据结构来管理。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值