CodeForces 496 E.Distributing Parts(贪心)

本文介绍了一种音乐会调度算法,通过将所有时间段按结束点排序,并使用集合记录曲目,实现曲目与演奏者的高效匹配,确保所有曲目都能被正确演奏。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description
有n首曲子,每首曲子的范围为ai~bi。有m个演奏家,每个演奏家的范围为ci~di,并且可以出演次数为ki次。如果ci<= ai<=bi<=di,则说明该曲子可以由演奏家演出。问是否存在合法方案使得所有曲子都能被演奏
Input
第一行为一个整数表示曲子的数量n,之后n行每行两个整数ai和bi表示这首曲子占的时间范围,然后为一整数m表示演奏家人数,之后m行每行三个整数ci,di和ki分别表示演奏家演奏的时间和出演次数
Output
如果存在合法方案使得所有曲子都可以被演奏完毕则输出YES并输出每首曲子分别由哪位演奏家演奏(输出一种可能情况即可),否则输出NO
Sample Input
3
1 3
2 4
3 5
2
1 4 2
2 5 1
Sample Output
YES
1 1 2
Solution
将所有时间段放在同一个结构数组里按结束点升序排序,开一个set记录曲子,枚举结构体中的元素,如果这个时间段是演奏家的演奏阶段,那么set中存放的曲子结束时间显然都小于等于开始时间,一直二分找到开始时间最早的曲子(贪心的让当前演奏家演奏开始时间尽可能早的曲子)让这个演奏家演奏,然后从set中删去这首曲子,直到没有合适的曲子可以演奏或者这个演奏家的演奏次数用完为止;如果这个时间段是曲子的被演奏阶段,那么将这首曲子加入set即可,最后判断被演奏曲子的数量是否为n即可判断是否存在合法方案
Code

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<set> 
using namespace std;
#define maxn 111111
int n,m,pf[maxn];
struct node
{
    int l,r,num,op,id;
    //op表示是曲子还是演奏家
    //如果op=1说明是演奏家,l,r,num就表示其ci,di和ki,id表示其编号
    //如果op=0说明是曲子,l,r就表示其ai,bi,id表示其编号 
}a[2*maxn];
struct edge
{
    int l,id;
    bool operator<(const edge&e)const
    {
        if(e.l!=l) return e.l>l;
        return e.id>id; 
    }
    edge(int a=0,int b=0):id(a),l(b){}
}del;
set<edge>s;
set<edge>::iterator p;
bool cmp(node x,node y)
{
    if(x.r!=y.r)return x.r<y.r;
    if(x.op!=y.op)return x.op<y.op;
    return x.l<y.l;
}
int main()
{
    while(~scanf("%d",&n))
    {
        memset(pf,0,sizeof(pf));//第i首曲子是由第pf[i]个演奏家演奏的 
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d",&a[i].l,&a[i].r);
            a[i].op=0;a[i].id=i;
        }
        scanf("%d",&m);
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d",&a[i+n].l,&a[i+n].r,&a[i+n].num);
            a[i+n].op=1;a[i+n].id=i;
        }
        sort(a+1,a+n+m+1,cmp);//将这n+m个时间段按结束点排序,那么靠前的一定是结束时间早的 
        s.clear();
        int ans=0;//ans记录能够被演奏的曲子数目 
        for(int i=1;i<=n+m;i++)
            if(a[i].op)
            {
                while(s.size()&&a[i].num--)
                {
                    p=s.lower_bound(edge(0,a[i].l));//找到开始时间大于等于a[i].l的曲子中开始时间最小的 
                    if(p==s.end())break;
                    del=*p; 
                    s.erase(p);//删掉这首曲子
                    pf[del.id]=a[i].id;//记录这首曲子的演奏者 
                    ans++;//被演奏完成的曲子数量加一 
                }
            }
            else
                s.insert(edge(a[i].id,a[i].l));
        if(ans==n)//所有曲子均被演奏完成则说明存在合法方案 
        {
            printf("YES\n");
            for(int i=1;i<=n;i++)   
                printf("%d%c",pf[i],i==n?'\n':' ');
        }
        else printf("NO\n");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值