您的位置:首页 > 其它

poj1180 dp斜率优化

2013-11-18 16:01 369 查看
解题报告

题目
http://poj.org/problem?id=1180

题目大意
:给定n个工作,可以任意分组,最后每个工作的花费是O[i]*f[i],其中O[i]是i所在分组整体被完成的时间,给定开始时间,机器启动时间S,求完成所有任务最小花费。

算法
:动态规划 +

斜率优化

思路
:首先想到了dp[i] = min{dp[j]
+ (S + O[j] + sum[i] – sum[j]) * f[i] ) (j <
i)但是这是二维的方程,需要优化成一维,但是这个式子很难化解成f[i] – f[j] = k (g[i] – g[j]) +
b的形式,而且如果将j和i分在一组,O[j]的值也会改变,无法用斜率搞,最后看了网上大牛才知,设定状态

Dp[i]
= min{dp[j] + (S + sumt[i] – sumt[j] ) * sumf[i]
{sumt[i] =t[i] + t[i + 1]…….}, sumf[i] = f[i] + f[i +
1]….

然后化解这个式子就能斜率优化了。这里处理O[i]也算是一个技巧了,将由工作i导致的i之后的花费加到i上,这样每次的开始时间都成为了0,从后往前dp即可,其他都一样。

提交情况 Accepted 1


经验与收获

对斜率优化理解还是不到位。

AC
code:

#include <stdio.h>



#define MAXN 10010



intsumt[MAXN], sumf[MAXN], dp[MAXN], strack[MAXN], S,
T[MAXN], F[MAXN], n;



bool rise(int k,
int j, int i){


return (dp[k] - dp[j])
<= sumf[i] * (sumt[k] - sumt[j]);

}



boolturn_right(int p,
int q, int r){


int t1 = (dp[p] - dp[q]) * (sumt[q]
- sumt[r]);


int t2 = (dp[q] - dp[r]) * (sumt[p]
- sumt[q]);


return t1 >=
t2;

}



int main(){


int res, top, i;


sumt[0] = sumf[0] = 0;


while(~scanf("%d", &n)){


scanf("%d",
&S);


for(i = 1; i <= n; i
++)


scanf("%d %d",
&T[i], &F[i]);


sumt[n + 1] = sumf[n + 1] = 0;


for(i = n; i > 0; i
--){


sumt[i] = sumt[i + 1] + T[i];


sumf[i] = sumf[i + 1] + F[i];


}




strack[0] = dp[n + 1] = top = res = 0;


strack[++top] = n;


dp
= (S + sumt
) * sumf
;


for(i = n - 1; i >
0; i --){


for(; res < top
&& rise(strack[res + 1],
strack[res], i); res ++);


dp[i] = dp[strack[res]] + (S + sumt[i] - sumt[strack[res]]) *
sumf[i];


while(top > 0
&& turn_right(strack[top - 1],
strack[top], i)) --top;


strack[++top] = i;


if(res > top) res =
top;


}


printf("%d\n",
dp[1]);


}


return 0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: