假设每一层的水都是本质不同的,
如果存在一种最优方案从第i层开始减压,那么第i层的水一定要流到第n层
可以用反证法证明:
若存在一种最优方案第i层的水没有流到第 n 层,
而是在第j层被阻挡了 (j>i),
那么修改这个方案,从第j+1层开始减压 , 第 j+1 到第 n 层的操作不变,
代价更小,而最后的效果相同,
所以这不是最优方案,推出矛盾,原结论成立。
于是可以枚举 i,从第 i 层开始减压,计算代价,选出代价最小的方案
时间复杂度 O(n2),但这里n的范围较大,会超时
可以有优化
如果从第 i 层开始减压,第 j 层自动减压的条件是sumw(i,j)>v(j)
即pre(j)−pre(i−1)>v(j)
=>pre(j)−v(j)>pre(i−1)
当对第i层减压时
totcost=sumc(i,n)−ncost(i)
ncost(i)=Σcost(j) | pre(j)−v(j)>pre(i−1) & i<j<=n
因为pre(i)是单调上升的,
而注意到第 j 层自动减压的条件:
pre(j)−v(j)>pre(i−1)& i<j<=n
所以 ncost(i) 是单调下降的
所以可以有这样一个算法:
1,处理 pre()
2,处理 ncost() ,维护一个大根堆,储存key=pre(j)−v(j)和cost(j)
从 n 到 1 枚举 i,ncost(i)=ncost(i+1)
ncost(i)+=heap[top].cost,pop(top) | pre(i−1)<heap[top].key
3,枚举减压起始层,计算代价,求出最优方案
时间复杂度O(N∗logN)。
#include<cstdio>
#include<cstdlib>
#include<queue>
#include<utility>
using namespace std;
const int MAXN = 15005 , INF = (1<<30) - 1;
int n;
struct station{int w,l,p;}b[MAXN] = {0};
priority_queue<pair<int,int> > heap;
int pre[MAXN] = {0};
int ans , st , cost;
int main()
{
#ifndef ONLINE_JUDGE
freopen("sgu148.in","r",stdin);
freopen("sgu148.out","w",stdout);
#endif
scanf("%d",&n);
for(int i = 1; i <= n ;i++)
{
scanf("%d%d%d",&b[i].w,&b[i].l,&b[i].p);
pre[i] = pre[i-1] + b[i].w;
}
// sum(j , i) > L(i) pre[i] - pre[j-1] > L[i]
// pre[j-1] < pre[i] - L[i]
cost = 0 , st = 0 ,ans = INF;
for(int i = n; i >= 1;i--)
{
for(;!heap.empty() && heap.top().first > pre[i-1];heap.pop())
cost -= heap.top().second;
heap.push(make_pair(pre[i] - b[i].l , b[i].p));
cost += b[i].p;
if(cost < ans)
{
ans = cost;
st = i;
}
}
for(int i = st , sumf = 0; i <= n; i++)
{
sumf += b[i].w;
if(sumf <= b[i].l)
printf("%d\n",i);
}
#ifndef ONLINE_JUDGE
fclose(stdin);
fclose(stdout);
#endif
}
版权声明:本文为博主原创文章,未经博主允许不得转载。