Codeforces Round #189 (Div. 1) Kalila and Dimna in the Logging Industry 斜率DP

题目链接:http://codeforces.com/problemset/problem/319/C

以前不知道斜率DP优化,遇到这题,学会了,要加深印象:

题意大致是砍树,不一定按顺序看,目的是为了使充电费用最低,看完标号最大的树,充电就不再需要费用,所以关键在于求砍完标号最大的树所需要的最小花费,DP优化,记dp[i]为砍倒第i棵树所需要的最小花费,所以所以对于dp[n], dp[n] = min{ dp[j] + b[j] * a[n]}, j = 1, 2, 3, ...... n - 1。注意这里题目条件单调的,这可以作为斜率DP的一个标志。

分析如下:设现在要求dp[k], 在k之前的任意两个数,我们设为i, j, 且i < j < k; 那么dp[j] + b[j] * a[k] 和 dp[i] + b[i] * a[k]两个方案那个更优呢?作差比较, 移项化简得:如果 (dp[j] - dp[i]) / (bi - bj) < ak 则 方案 j 优于方案 i。(这里要注意吧bi递减,移项变号),我们把左边看作一个两点的斜率,得到一个函数G(j, i)如果G(j, i)< ak 则 j 优于 i。可以删除 i 方案。且以后 j 之后再有其他数,i 也不可能成为最优方案,因为 j 比 i 优。另外 当G(j, i) < G ( k , j )时, 可以删除 j 方案,因为这样 j 永远不会是最优方案, 以上两步优化维护了一个单调队列, 图形上看相邻两点的斜率单调递增或递减,所以叫斜率DP优化吧?原来复杂度n*n的降为了O(n),因为每个方案之进入队列一次,被提出以后不再加入。

代码如下:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<queue>
#include<algorithm>
#include<stack>
#include<deque>
#include<set>
#include<vector>
#include<iomanip>
#include<cctype>
#include<string>
#include<memory>
#include<map>
#include<sstream>
#include<cassert>
#define mem(a) memset(a, 0, sizeof(a))
typedef long long LL;
typedef double dou;
const int Mod = 1000000007;
const double eps = 1e-8;
const LL inf = 1e18;
const int inf1 = 1e9;
using namespace std;
const int N = 100005;
LL dp[N], qu[N], a[N], b[N];

int main()
{
		LL n, i, j, st, en, s = 1;
		cin >> n;
		for (i = 1; i <= n; ++i)
				cin >> a[i];
		for (i = 1; i <= n; ++i)
				cin >> b[i];
		st = 1;
		en = 2;
		qu[1] = 1;
		dp[1] = 0;
		for (i = 2; i <= n; ++i)
		{
				while (st < en - 1 && (dp[qu[st + 1]] - dp[qu[st]]) < (b[qu[st]] - b[qu[st + 1]]) * a[i])
						st++;
				dp[i] = dp[qu[st]] + b[qu[st]] * a[i];
				while (st < en - 1 && en > 2 && (dou) (dp[qu[en - 1]] - dp[qu[en - 2]]) / (b[qu[en - 2]] - b[qu[en - 1]]) >= (dou) (dp[i] - dp[qu[en - 1]]) / (b[qu[en - 1]] - b[i]))
						en--;
				qu[en++] = i;
		}
		cout << dp[n] << endl;
		return 0;
}

参考资料:

http://www.cnblogs.com/ka200812/archive/2012/08/03/2621345.html

http://hi.baidu.com/prowindy/item/aa9ae4e285a6a4295b7cfb81?qq-pf-to=pcqq.c2c

推荐题目:http://acm.hdu.edu.cn/showproblem.php?pid=3507



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值