【BZOJ 1148】【CTSC 2008】挂缀【BZOJ 1 148】【CTSC 2008】挂缀

本文介绍了一道经典的CTSC 2008挂坠问题,通过分析两种常见但错误的贪心策略,提出了正确的解决思路——按照C+W的和进行排序,并采用贪心算法来解决第一问,同时通过维护链中最大重量来解答第二问。

BZOJ 1 148】【CTSC 2008】挂缀

这题显然是个贪心,然而我们应该如何贪才能得到最优解= =。。。。

假设我们按重量升序贪心,那我们可以得到反例(假设在挂缀底部):设有i,j,j<iW_j<W_i

那么当C_i<W_j,W_i<C_j时,应该选i而不是j

假设我们按拉力升序贪心,依旧可以得到反例(假设在挂缀顶部,S为链以下重量和):设有i,j,j<i,C_j<C_i

那么当C_i<S+W_j,S+W_i<C_j时,应该先选i当第二高的,而非链顶

= =那如何贪心呢,观察以上两个式子,我们发现C_i+W_i<C_j+W_j,于是我们按$C+W$拍升序贪心。然而这样我们只保证了第一问,第二问需要我们维护原链中最大重量。贪心策略是,能挂到当前链顶就挂,不能挂重量看是否小于链中最大重量,小于则替换(由于排序的方法,替换的挂缀C值只能大于原位置C值,因此可替换),复杂度O(n log n)code

#include<iostream> 
#include<cstdio> 
#include<cstring> 
#include<algorithm> 
#include<queue> 
using namespace std; 
struct hq{ 
    long long wgt,f,sum; 
    bool operator <(hq const &a) const
      {return sum<a.sum;} 
}a[1000001]; 
int n; 
long long nowwgt=0,nowl=0; 
priority_queue<int> q; 
int main() 
{ 
    int i; 
    scanf("%d",&n); 
    for (i=1;i<=n;++i) 
      { 
        scanf("%I64d%I64d",&a[i].f,&a[i].wgt); 
        a[i].sum=a[i].f+a[i].wgt; 
      } 
    sort(a+1,a+n+1); 
    for (i=1;i<=n;++i) 
      { 
        if (nowwgt<=a[i].f) {q.push(a[i].wgt); nowl++; nowwgt=nowwgt+a[i].wgt;} 
        else if (q.top()>a[i].wgt) {nowwgt=nowwgt-q.top()+a[i].wgt; q.pop(); q.push(a[i].wgt);} 
      } 
    printf("%lld\n%lld\n",nowl,nowwgt); 
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值