题314.csp-2203 P1未初始化警告&P2出行计划&P3计算资源调度器&P4通信系统管理

本文介绍了三道编程竞赛题目:未初始化警告、出行计划的最优解决方案以及计算资源调度器的设计。针对未初始化警告,通过遍历和计数解决;出行计划问题利用差分和前缀和优化复杂度;计算资源调度器通过筛选和更新策略实现高效分配。这些解题策略展示了算法在实际问题中的应用。
摘要由CSDN通过智能技术生成


题314.csp-2203 P1未初始化警告&P2出行计划&P3计算资源调度器


一、P1未初始化警告

1.题目

在这里插入图片描述
在这里插入图片描述

2.题解

#include <bits/stdc++.h>

using namespace std;

const int maxn=1e5+1;

int n,k;
int flag[maxn];
int cnt;

int main()
{
    cin>>n>>k;
    for(int i=0;i<k;i++)
    {
        int x,y;
        cin>>x>>y;
        if(y!=0&&!flag[y])//ay不是常量且ay未被赋值
        {
            cnt++;//未初始化变量数++
        }
        flag[x]=1;
    }
    cout<<cnt;
}

二、P2出行计划

1.题目

在这里插入图片描述
在这里插入图片描述

2.题解

本题给定n个出行的开始时间ti以及出行对应地点需持ci时间内的核酸检测,求对于m个核酸检测时间点询问,在k时间出结果以后最多出行的个数。
暴力求解,十分显然,无非就是对于每次询问,把可出行的时间的上界与下界通过k,q,c算出来,看开始出行时间t是否在那个时间区间内就好,这样每次询问得做n次计算,对于m次询问,时间复杂度自然是平方级别的,不满足本题满分的要求。
对于本题的正解,我们可以用差分+前缀和。如何想到的?易知,暴力解法,每个出行点可出行需满足的条件为q+k<=ti<=q+k+ci-1,这个条件不是很好用,我们不妨将其变形,化成ti-ci-k+1<=q<=ti-k,推导过程如下:
在这里插入图片描述
则问题就变为了看q这个点能够被放在多少个[t-c-k+1,t-k]区间里,但是单纯这样去想又会发现每次询问仍然要拿着q对那n个区间去比对,时间和原先暴力解法一样。此时我们不妨转换思考的角度,看q这个点能够被放在多少个[t-c-k+1,t-k]区间里这个问题其实等价于用n个区间把一堆时间点给覆盖了,看问的那个时间点被多少个区间所覆盖的问题。
这样我们其实可以在输入n个出行点信息的时候把对应区间求出,然后把这个区间内所有的时间点对应的结果(即被覆盖数,原先为0)都+1,然后在后面询问的时候,直接输出那个时间点对应的结果就好。那么如何可以快速的将一个区间内的值进行统一的修改呢?显然就会想到差分了。对于给定结果数组对应的差分数组b[l]+1,b[r+1]-1,等价于对其原数组,即结果数组cnt[l~r]+1。之后做完输入操作之后,求前缀和得到结果数组就好。
代码如下:

#include <bits/stdc++.h>

using namespace std;

const int maxn=2e5+2;

int n,m,k;
int cnt[maxn],b[maxn];//结果数组,结果数组对应的差分数组

int main()
{
    cin>>n>>m>>k;
    int maxr=0;
    for(int i=0;i<n;i++)
    {
        int t,c;
        cin>>t>>c;
        int l=t-c-k+1,r=t-k;//确定区间左端点与右端点
        maxr=max(maxr,r);
        //设结果对应的差分数组,用于对[l,r]做区间修改(cnt[l~r]+1,即覆盖该范围的区间个数+1,对应对b[l]+=1,b[r+1]-=1)
        b[max(1,l)]+=1;//因为l可能为非正数,此时该区间覆盖的点最小显然可从1开始
        b[max(r,0)+1]-=1;//因为r可能为非正数,此时该区间覆盖的点最大显然可到1
    }
    for(int i=1;i<=maxr;i++)//对差分数组求前缀和得到结果数组
    {
        cnt[i]=cnt[i-1]+b[i];
    }
    for(int i=0;i<m;i++)
    {
        int q;
        cin>>q;
        cout<<cnt[q]<<endl;//对结果数组做单点询问,得到结果
    }
}

三、P3计算资源调度器

1.题目

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.题解

#include <bits/stdc++.h>

using namespace std;

const int maxn=1100;

struct Node//计算节点
{
    int id;//节点编号
    int field;//节点所属可用区
    int tasknum;//节点运行的任务数量
} node[maxn];

unordered_map<int,set<int>> appfield;//应用i放置的可用区
unordered_map<int,set<int>> appnode;//应用i放置的计算节点的id
int n,m;

void init()//计算节点初始化
{
    for(int i=1; i<=n; i++)
    {
        int field;
        cin>>field;
        node[i].id=i;
        node[i].field=field;
        node[i].tasknum=0;
    }
}

vector<Node> select(int a,int na,int pa,int paa,int paar)//节点筛选:得到a应用对应的其中一个任务的可选任务节点
{
    vector<Node> res,tmp;
    for(int i=1; i<=n; i++) res.push_back(node[i]);//先把所有计算节点当作可选选入
    if(na>0)//节点亲和性过滤
    {
        for(auto it=res.begin(); it!=res.end(); )
        {
            if((*it).field!=na) res.erase(it);//可用区得是na的计算节点才能被保留
            else it++;
        }
    }
    if(pa>0)//任务亲和性过滤
    {
        for(auto it=res.begin(); it!=res.end(); )
        {
            if(appfield[pa].find((*it).field)==appfield[pa].end()) res.erase(it);//pa应用有的计算节点才能被保留
            else it++;
        }
    }
    if(paa>0)//任务反亲和性过滤
    {
        for(auto it=res.begin(); it!=res.end(); )
        {
            if(appnode[paa].find((*it).id)!=appnode[paa].end())//paa应用没有的计算节点才能被保留
            {
                tmp.push_back(*it);//暂存过滤节点
                res.erase(it);
            }
            else it++;
        }
        if(res.size()==0&&paar==0)//如果过滤完一个节点都没有了,则看看是不是只是尽量满足任务反亲和
        {
            for(int i=0; i<tmp.size(); i++) res.push_back(tmp[i]);//把过滤掉的节点塞回去
        }
    }
    return res;
}

int main()
{
    cin>>n>>m;
    init();
    int g;cin>>g;
    while(g--)
    {
        int f,a,na,pa,paa,paar;
        cin>>f>>a>>na>>pa>>paa>>paar;
        for(int i=0; i<f; i++)//按照题目说的启动一组(f,...)和启动f组(1,...)是一样的,所以直接做f次计算节点筛选操作
        {
            vector<Node> res=select(a,na,pa,paa,paar);//节点筛选
            if(res.size()>0)
            {
                //得到任务数最少且编号最小的节点
                Node resnode={maxn,0,2000};
                for(int i=0; i<res.size(); i++)
                {
                    if(res[i].tasknum<resnode.tasknum) resnode=res[i];
                    else if(res[i].tasknum==resnode.tasknum&&res[i].id<resnode.id) resnode=res[i];
                }
                //更新节点使用情况
                for(int i=1; i<=n; i++)
                {
                    if(node[i].id==resnode.id)
                    {
                        node[i].tasknum++;
                        appfield[a].insert(node[i].field);
                        appnode[a].insert(node[i].id);
                        break;
                    }
                }
                cout<<resnode.id<<" ";
            }
            else cout<<"0"<<" ";
        }
        putchar('\n');
    }
}

四、P4通信系统管理

1.题目

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.题解

//运行超时,10分
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef pair<int,ll> pil;
const int maxn=1100;

struct Info
{
    int u,v;
    int x;
    int deadline;
};

int n,m;
vector<Info> table;
ll G[maxn][maxn];

void update(int d)
{
    for(auto info:table)
    {
        if(d==info.deadline) G[info.u][info.v]-=info.x,G[info.v][info.u]-=info.x;
    }
}

void apply(int d,int u,int v,int x,int y)
{
    table.push_back({u,v,x,d+y});
    G[u][v]+=x,G[v][u]+=x;
}

int check(int u)
{
    int ans=0;
    for(int v=1;v<=n;v++)
    {
        if(u==v) continue;
        if(G[u][v]>G[u][ans]) ans=v;
    }
    return ans;
}

void queryIslandNum()
{
    int cnt=0;
    for(int u=1;u<=n;u++)
    {
        int flag=0;
        for(int v=1;v<=n;v++)
        {
            if(u==v) continue;
            if(G[u][v])
            {
                flag=1;
                break;
            }
        }
        if(!flag) cnt++;
    }
    cout<<cnt<<endl;
}

void queryRelNum()
{
    int cnt=0;
    int rel[maxn];
    for(int u=1;u<=n;u++)
    {
        rel[u]=check(u);
    }
    for(int u=1;u<=n;u++)
    {
        int v=rel[u];
        if(rel[v]==u) cnt++;
    }
    cout<<cnt/2<<endl;
}

int main()
{
    cin.tie(0);cout.tie(0);
    cin>>n>>m;
    for(int i=0;i<m;i++)
    {
        update(i);
        int k;cin>>k;
        while(k--)
        {
            int u,v,x,y;
            cin>>u>>v>>x>>y;
            apply(i,u,v,x,y);
        }
        int l;cin>>l;
        while(l--)
        {
            int u;cin>>u;
            cout<<check(u)<<endl;
        }
        int p,q;
        cin>>p>>q;
        if(p) queryIslandNum();
        if(q) queryRelNum();
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值