sgu 148 B-Station 枚举+小根堆

本文讨论了一个关于水坝水量分配与成本优化的问题。通过引入优先队列和小根堆的数据结构,作者提出了一个高效的算法来确定最优的爆破方案,以使水坝的最底层超载。算法首先通过枚举起点并检查水量是否超过限制来判断是否自然超载,然后使用堆优化决策过程,最终计算出最小成本的爆破方案。

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

      放假前就看过这题,一点思路也没-..看题解都没看懂...今终于A掉了...

      一个水库分为N层,每层有一定量的水W,和一个承载上限L,以及爆破本层需要的花费.如果某层的水量超过了上限,或者是被炸掉了,这层的水就会落到下一层中(记为超载)。现在一些人想要使最下面一层既第N层超载,问在花费最少的情况下,需要爆破哪些层?

      现在看题解还是没看懂...不过倒是受到了点启发。首先考虑一个n^2的做法,枚举水开始下落的起点,从这个点开始向下扫描一遍,如果某一层加上起点到这层之间水量的和足以超过上限,那么这层自然超载,否则就需要炸掉这层,并把花费加上。因为n是15000,这中做法显然会T掉,所以想办法优化..对于每一层,记Si=(Li-Sum(1,i)),对于每一层i,如果当前开始下落的起点为st的话,若Si+sum(1,st-1)<0)说明是可以自然超载的,否则就需要爆破。虽然对于每一层,是否可以自然超载取决于st,但是Si之间的大小关系却是有序的,所以考虑用一个小根堆(优先队列也行,更方便点),保存当前st下,需要爆破的各个层数。这样,从N开始向1枚举st,每次循环,首先检测堆顶的S+sum(1,st-1)是否小于0,不断删除堆顶元素直到S+sum(1,st-1)>=0此时堆中所有的元素都是需要爆破的..统计一下花费,枚举每个st时更新下花费的最小值和起点位置这题就OK了。

#include <iostream>
#include <cstdio>
#include <queue>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn=25500;
int n,m;
int sum[maxn];
struct node
{
    int w,l,s,cost;
    node()
    {

    };
    bool operator>(const node& b)const
    {
        return s<b.s;
    }
    bool operator<(const node& b)const
    {
        return s>b.s;
    }
}a[maxn];

int p,q;
int main()
{
//    freopen("in.txt","r",stdin);
    scanf("%d",&n);
    priority_queue<node> que;

    for (int i=1; i<=n; i++)
    {
        scanf("%d%d%d",&a[i].w,&a[i].l,&a[i].cost);
        sum[i]=sum[i-1]+a[i].w;
    }
    for (int i=1; i<=n; i++)
    {
        a[i].s=a[i].l-sum[i];
    }
    int ans=a[n].cost;
    int st=n;
    int fe=a[n].cost;
    que.push(a[n]);
    for (int i=n-1; i>=1; i--)
    {
        fe+=a[i].cost;
        while (!que.empty())
        {
            node tp=que.top();
            if (tp.s+sum[i-1]<0)
            {
                que.pop();
                fe-=tp.cost;
            }
            else break;
        }
        if (fe<ans)
        {
            ans=fe;
            st=i;
        }
        que.push(a[i]);

    }
    for (int i=st; i<=n; i++)
    if (a[i].l>=sum[i]-sum[st-1])
    {
        printf("%d\n",i);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值