SGU 148.B-Station

时间限制:0.25s

空间限制:4M 

题目

        在离著名的国家Berland不远的地方,有一个水下工作站。这个工作站有N层。已知:是第层装有Wi的水,最多可以容纳Li的水,恐怖分子炸毁第i的代价是Pi。第i层一旦被炸毁,该层所有的水都将倾泻到第i+1层。如果某一层的水量超过了它的容量(即Li),那么该层就将自动被毁坏,所有的水也会倾泻到下一层。

        Pivland的恐怖分子想要用最少的钱毁掉第N层,现在他雇佣你来计算,需要炸毁哪些层。

 

 

输入

 

      第一行有一个自然数N(1<=n<=15000)。接下来的N行,每行3个整数Wi, Li, Pi(0<=Wi,Li,Pi<=15000)。

 

输出

 

     输出需要炸毁的层的编号。

 

 

 

 


 

Solution:

                 最简单的想法是,从第一层开始枚举炸毁的第一层,但时间复杂度是O(n2)的.

               s[i] 代表 从第1层到i层的水量和.l[i]为第i层的水量,c[i]是炸毁代价.

               于是进一步考虑,从第i层开始炸毁,如果第 i+k层不需要炸毁,那么一定是s[i+k]-s[i-1]>l[i+k]。

               

               从下往上推的话,

               f[i]是从i层开始炸毁的代价。

               如果炸毁i-1,且s[i]-s[i-2]>l[i],那么从第i-1层开始炸毁的代价是f[i]+c[i-1]-c[i];

             从第k层开始炸毁时只要将第i(k<i<=n)层里(s[i]-s[k-1]>l[i]) 层里之前算作炸毁的层的c[i]减去,并标记没被炸毁.

               用优先队列优化的话将快很多,只要将当前炸毁的层入队,当满足s[i]-s[k-1]>l[i]时,出对并减去c[i];

 

code

 

#include<stdio.h>
#include<utility>
#include<queue>
using namespace std;
const int INF = 15000 + 9;
priority_queue< pair<int, int> > heap, ansheap;
int l[INF], p[INF], s[INF];
int n, w, i;
int sum, ans = 1e9;
int main()
{
	scanf ("%d", &n);
	for (i = 1; i <= n; ++i){
		scanf ("%d%d%d", &w, l + i, p + i);
		s[i] = s[i - 1] + w;
	}
	for (i = n; i; --i){
		for (; !heap.empty() && heap.top().first > s[i - 1]; heap.pop() )
			sum -= p[heap.top().second];
		heap.push (make_pair (s[i] - l[i], i) );
		sum += p[i];
		if (sum < ans){
			ans = sum;
			ansheap = heap;
		}
	}
	for (; !ansheap.empty(); ansheap.pop() )
		printf ("%d\n", ansheap.top().second);
	return 0;
}

 

  

 

转载于:https://www.cnblogs.com/keam37/p/3844378.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值