P3093 [USACO13DEC]牛奶调度Milk Scheduling - 贪心+二叉堆

传送门

思路:一个贪心策略就是“在不挤超过截至时间的奶牛的前提下,尽量挤奶量大的奶牛”。So我们将奶牛按截至日期从小到大排序,对于每个截至时间t,将所有截至时间为t的奶牛的奶量加入一个大根堆,只留下前t大的数,剩下的直接删去。由于priority_queue没有clear函数,所以我手写了一个堆。。。(请不要问我为什么不用小根堆,每次弹出前size()-t个数,但这样做会WA得很惨。。。)

AC Code:(代码略鬼畜,但我觉得应该没多少人看我这博客吧。。)

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=10000+10;
struct node{
    int d,g;//d[]=deadline g[]=gain
}a[N];
bool cmp(const node a,const node b){
    return a.d<b.d;
}
int heap[N],siz;
void up(int p){//向上维护大根堆 
    while(p>1){
        //p=子节点 p/2=父节点 
        if(heap[p]>heap[p/2]) { //子节点大于父节点 不满足大根堆性质 
        //小根堆将>改为<即可 
            swap(heap[p],heap[p/2]);
            p/=2;//向上维护大根堆 
        }
        else break;//满足大根堆要求 
    }
}
void insert(int x){//向堆中插入元素 
    heap[++siz]=x;
    up(siz);
}
int top(){//返回堆顶元素 
    return heap[1];
} 
void down(int p){//向下维护大根堆 
    int s=p<<1;//儿子编号 初始为左儿子 
    while(s<=siz){
        if(s<siz&&heap[s]<heap[s+1]) s++;//将较大的儿子换为父节点 
        if(heap[s]>heap[p]){
            swap(heap[s],heap[p]);
            p=s,s=p<<1;//父节点变为较大的儿子,更新儿子编号 
        } 
        else break;
    }
} 
void pop(){//弹出堆顶元素
    heap[1]=heap[siz--];//将堆顶元素换为堆末尾元素,然后删去末尾,避免直接删除堆顶的复杂操作 
    down(1);
}
int tmp[N],tot;
int main(){
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d%d",&a[i].g,&a[i].d);
    sort(a+1,a+n+1,cmp);
    for(int i=1;i<=n;i++){
        int T=a[i].d;insert(a[i].g);
        while(a[i+1].d==T){
            insert(a[i+1].g);i++;
        }
        if(siz>T) {
            for(int i=1;i<=T;i++) tmp[++tot]=top(),pop();
            siz=0;
            for(int i=1;i<=tot;i++) insert(tmp[i]);
            tot=0;
        }
    }
    int ans=0;
    while(siz) ans+=top(),pop();
    printf("%d\n",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Loi-Brilliant/p/9419450.html