poj2970 The lazy programmer 【优先队列】

本文介绍了一种解决程序员合同调度问题的算法,旨在通过额外支付最小成本确保所有合同在截止日期前完成。算法首先按截止日期对合同进行排序,然后使用优先队列存储已完成合同及其时间消耗。当新合同时间不足时,从历史合同中选取单位成本最高的合同,通过付费缩短其完成时间,以腾出更多时间给当前合同,直至所有合同按时完成。

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

A new web-design studio, called SMART (Simply Masters of ART), employs two people. The first one is a web-designer and an executive director at the same time. The second one is a programmer. The director is so a nimble guy that the studio has already got N contracts for web site development. Each contract has a deadline di.

It is known that the programmer is lazy. Usually he does not work as fast as he could. Therefore, under normal conditions the programmer needs bi of time to perform the contract number i. Fortunately, the guy is very greedy for money. If the director pays him xi dollars extra, he needs only (bi − ai xi) of time to do his job. But this extra payment does not influent other contract. It means that each contract should be paid separately to be done faster. The programmer is so greedy that he can do his job almost instantly if the extra payment is (bi ⁄ ai) dollars for the contract number i.

The director has a difficult problem to solve. He needs to organize programmer’s job and, may be, assign extra payments for some of the contracts so that all contracts are performed in time. Obviously he wishes to minimize the sum of extra payments. Help the director!

Input

The first line of the input contains the number of contracts N (1 ≤ N ≤ 100 000, integer). Each of the next N lines describes one contract and contains integer numbers aibidi (1 ≤ aibi ≤ 10 000; 1 ≤ di ≤ 1 000 000 000) separated by spaces.

Output

The output needs to contain a single real number S in the only line of file. S is the minimum sum of money which the director needs to pay extra so that the programmer could perform all contracts in time. The number must have two digits after the decimal point.

Sample Input

2
20 50 100
10 100 50

Sample Output

5.00

 

题意:有n个合同,截止日期分别是di,有个程序员,完成每个合同的时间是bi。对于合同i,给他x元钱,相应完成时间变为bi-ai*x。求需要最少的钱数,保证该程序员按时完成所有合同。

算法:所有合同,按照截止日期排序。维护一个优先队列,存储历史上完成的合同及相应使用时间。每下一个合同时间不够用,就在历史上选择ai最大的合同,将其时间用钱来买,从而增加当前合同可以使用的时间。统计付钱总额。

代码:

#include <iostream>
#include <cstdio>
#include <vector>
#include <queue>
#include <algorithm>

#define llint long long
#define LEN 100000

double ans;
int n;
int d[LEN], a[LEN], b[LEN], t[LEN];

struct pair2{
    int a,len;
    bool operator < (const pair2 &tmp) const{
        return a<tmp.a;
    }
}pairs[LEN];
std::priority_queue<pair2*> pq;

void input();
void work();
void output();

int main(){
    input();
    work();
    output();

    return 0;
}

void input(){
    scanf("%d", &n);
    for(int i=0;i<n;i++){
        scanf("%d %d %d", &a[i], &b[i], &d[i]);
        t[i]=i;
    }
}
bool compareSort(const int& i, const int& j){
    return d[i]<d[j];
}
void work(){
    int pair_i=0, cur=0;
    std::sort(t, t+n, compareSort);
    for(int i=0;i<n;i++){
        int &index = t[i];
        int remain=d[index]-cur;
        if(remain>=b[index]){
            pairs[pair_i].a = a[index];
            pairs[pair_i].len = b[index];
            pq.push(&pairs[pair_i++]);
            cur += b[index];
        }else{
            pairs[pair_i].a = a[index];
            pairs[pair_i].len = remain;

            remain = b[index]-remain;
            while(!pq.empty()){
                pair2* p = pq.top();
                if (remain <= p->len){
                    p->len -= remain;
                    ans += double(remain)/a[index];
                    if (!p->len) pq.pop();
                    remain = 0;
                    break;
                }else{
                    ans += double(p->len)/a[index];
                    pq.pop();
                    remain -= p->len;
                }
            }
            if (remain){
                ans += double(remain)/a[index];
            }

            pq.push(&pairs[pair_i++]);
            cur = d[index];
        }
    }
}
void output(){
    printf("%.2f\n", ans);
}

 

转载于:https://www.cnblogs.com/jiu0821/p/10202425.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值