您的位置:首页 > 其它

sgu 148 分类: sgu 2015-03-11 13:14 49人阅读 评论(0) 收藏

2015-03-11 13:14 405 查看
假设每一层的水都是本质不同的,

如果存在一种最优方案从第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
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: