dp的斜率优化
对于刷题量我觉得肯定是刷的越多越好(当然这是对时间有很多的人来说。
但是在我看来我的确适合刷题较多的那一类人,应为我对知识的应用能力并不强。这两天学习的内容是dp的斜率优化。当然我是不太会的。
这个博文肯定也是不断更新的(随着我对斜率优化的不断深入的理解。
这两天做的题是一道经典的任务安排。
这道题是我两个星期前都想a掉的题。然后都是一个最简单的状态转移方程都推不出,真的是菜到家了。
然后翻书有一个最简单的状态转移方程,看了几分钟发现看的不是很懂而且我感觉这题应该自己思考。
所以扔下来了。两个星期回来再写,发现自己有了思路。
推了一个状态转移方程拿了60分比较骄傲,因为自己的dp很垃圾,现在我觉得才刚入门。
const int MAXN=;
int n,s;
int c[MAXN],t[MAXN];
int f[MAXN][MAXN],ans=INF;
//设f[i][j]表示前i个任务分成j组所能得到的最小值。目标min{f[n][i] i->1~n};
int main()
{
//freopen("1.in","r",stdin);
n=read();s=read();
for(int i=;i<=n;i++)t[i]=read(),c[i]=read(),t[i]+=t[i-],c[i]+=c[i-];
memset(f,,sizeof(f));
f[][]=;
for(int i=;i<=n;i++)
{
for(int j=;j<=i;j++)
{
for(int k=;k<=i;k++)//枚举这一组选择几项任务
{
f[i][j]=min(f[i][j],f[i-k][j-]+(s*j+t[i])*(c[i]-c[i-k]));
}
}
}
for(int i=;i<=n;i++){ans=min(ans,f[n][i]);}
put(ans);
return ;
}
这是自己打的代码能拿60分欸。复杂度n^3 超级高应为n<=MAXN
水了60心满意足。然后可以心安理得的翻书,书上和我定义的state不太一样。
const int MAXN=;
int n,s;
int c[MAXN],t[MAXN];
int f[MAXN][MAXN],ans=INF;
//设f[i][j]表示前i个任务分成j组所能得到的最小值。目标min{f[n][i] i->1~n};
int main()
{
//freopen("1.in","r",stdin);
n=read();s=read();
for(int i=;i<=n;i++)t[i]=read(),c[i]=read(),t[i]+=t[i-],c[i]+=c[i-];
memset(f,,sizeof(f));
f[][]=;
for(int i=;i<=n;i++)
{
for(int j=;j<=i;j++)
{
for(int k=;k<i;k++)//枚举上一组选取了多少任务
{
f[i][j]=min(f[i][j],f[k][j-]+(s*j+t[i])*(c[i]-c[k]));
}
}
}
for(int i=;i<=n;i++){ans=min(ans,f[n][i]);}
put(ans);
return ;
}
当然实现起来细节地方写自己的状态转移方程其实都是一样的。重点是状态不一样,值得借鉴。
然后考虑优化则么优化呢?经过书上的短短几行的点播。
它给出了一个其实不用枚举多少组,直接省掉一个for 和一个维度。比较好的思路。
书上说是费用提前计算的经典思想。
const long long MAXN=,INF=21474836474836ll;
long long n,s;
long long c[MAXN],t[MAXN];
long long f[MAXN];
//f[i]表示前i个任务分成过若干批完成执行的最小费用
int main()
{
//freopen("1.in","r",stdin);
n=read();s=read();
for(long long i=;i<=n;i++)t[i]=read(),c[i]=read(),t[i]+=t[i-],c[i]+=c[i-];
for(long long i=;i<=n;i++)f[i]=INF;
f[]=;
for(long long i=;i<=n;i++)
{
for(long long j=;j<i;j++)
{
f[i]=min(f[i],f[j]+t[i]*(c[i]-c[j])+s*(c[n]-c[j]));
}
}
put(f[n]);
return ;
}
这样的话就可以实现了分成多少组和当前这一组选多少个物品的结合。
这样的话很显然是比较优秀的做法。骤降一个维度和一个维度的时间。这种思想不错!
关键是数据范围还有更大的。n^2的做法也适应不了。
寒假回来 斜率优化大致懂了维护凸包什么的是关键所以代码中有解释自己打的哦!
//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<iomanip>
#include<cstring>
#include<string>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<utility>
#include<set>
#include<bitset>
#include<queue>
#include<stack>
#include<deque>
#include<map>
#include<vector>
#include<ctime>
#define INF 168430090000ll
using namespace std;
char buf[<<],*fs,*ft;
inline char getc()
{
return (fs==ft&&(ft=(fs=buf)+fread(buf,,<<,stdin),fs==ft))?:*fs++;
}
inline long long read()
{
long long x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return x*f;
}
inline void put(long long x)
{
x<?putchar('-'),x=-x:;
long long num=;char ch[];
while(x)ch[++num]=x%+'',x/=;
num==?putchar(''):;
while(num)putchar(ch[num--]);
putchar('\n');return;
}
const long long MAXN=;
long long n,s;
long long f[MAXN];//f[i]表示第i个任务完成所需最小费用
long long T[MAXN],F[MAXN],q[MAXN<<],l=,r=;
int main()
{
//freopen("1.in","r",stdin);
n=read();s=read();
for(long long i=;i<=n;i++)
{
T[i]=read();
F[i]=read();
T[i]+=T[i-];
F[i]+=F[i-];
}
memset(f,,sizeof(f));
f[]=;q[l]=;
for(long long i=;i<=n;i++)//枚举第i个任务
{
long long B=T[i]*F[i]+s*F[n];
long long K=T[i]+s;
while(l<r&&((f[q[l+]]-f[q[l]])<=K*(F[q[l+]]-F[q[l]])))l++;
f[i]=f[q[l]]-K*F[q[l]]+B;
while(l<r&&(f[q[r]]-f[q[r-]])*(F[i]-F[q[r]])>=(f[i]-f[q[r]])*(F[q[r]]-F[q[r-]]))r--;
//注意 除法变成乘法 大于等于号方向别搞反
q[++r]=i;
/*for(long long j=0;j<i;j++)//枚举前面的那个任务
{
//f[i]=min(f[i],f[j]+T[i]*(F[i]-F[j])+s*(F[n]-F[j]));
//f[i]=min(f[i],f[j]-T[i]*F[j]+T[i]*F[i]+s*F[n]-s*F[j]);
ans=min(ans,f[j]-K*F[j]);
//K显然是斜率 每一个f[i]的求出都是以F[j]为变量对应一个f[j]
//显然当斜率......想通就可以
f[i]=ans+B;f[i]=f[j]-K*F[j]+B;
f[j]=f[i]-B+k*f[j];显然这是一个点斜式
//截距为f[i]-B;截距越小f[i]越小
}*/
}
put(f[n]);
return ;
}
然后我们会发现一个东西就是我不断出队队首的原因 也就是寻找一个点 (设点a,b,c,此时斜率为k,k>kab,k<kac)b这个点就是最优转移决策。
这个东西是一定的呢!蒟蒻不会证明但是会画图 把所有情况画出来 发现了或者是“显然”的发现了这一特异性的结论。
例题:
这里的T 有可能是负数,那么我们的斜率T[i]+s就不再具有单调性如果像上述方法直接把队首出队的话那么当前斜率可能依赖之前队首的点
所以这里我们要维护整个下凸的凸包然后每次通过在这个凸包上二分来寻找最优决策。
二分不好写 RE WA 很难调但是坚持 就能调对。
//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<iomanip>
#include<cstring>
#include<string>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<utility>
#include<set>
#include<bitset>
#include<queue>
#include<stack>
#include<deque>
#include<map>
#include<vector>
#include<ctime>
#define INF 168430090
using namespace std;
char buf[<<],*fs,*ft;
inline char getc()
{
return (fs==ft&&(ft=(fs=buf)+fread(buf,,<<,stdin),fs==ft))?:*fs++;
}
inline long long read()
{
long long x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return x*f;
}
inline void put(long long x)
{
x<?putchar('-'),x=-x:;
long long num=;char ch[];
while(x)ch[++num]=x%+'',x/=;
num==?putchar(''):;
while(num)putchar(ch[num--]);
putchar('\n');return;
}
//任务安排升级版 T可能为负值 RE:应将除法变成乘法小心0
const long long MAXN=;
long long n,s;
long long T[MAXN],F[MAXN];
long long f[MAXN];//f[i]表示第i个任务完成所需最小时间
long long q[MAXN],h,t;
int g[MAXN],l,r;
long long find(long long x)
{
if(h==t)return h;
long long l=h,r=t;
while(l+<r)
{
long long mid=(l+r)>>;
int tmp1=(F[q[mid]]-F[q[mid-]]);
int tmp2=(F[q[mid+]]-F[q[mid]]);
long long K1=((f[q[mid]]-f[q[mid-]]));
long long K2=((f[q[mid+]]-f[q[mid]]));
if(K1<x*tmp1&&K2>x*tmp2)return mid;
if(K1<x*tmp1&&K2<x*tmp2)l=mid;
else r=mid;
}
int tmp=(F[q[r]]-F[q[l]]);
long long K3=((f[q[r]]-f[q[l]]));
if(K3<x*tmp)return r;
if(K3>x*tmp)return l;
return r;
}
int main()
{
freopen("1.in","r",stdin);
n=read();s=read();
for(long long i=;i<=n;i++)
{
T[i]=read();
T[i]+=T[i-];
F[i]=read();
F[i]+=F[i-];
}
for(long long i=;i<=n;i++)
{
long long K=T[i]+s;
long long B=F[i]*T[i]+s*F[n];
long long tmp=find(K);
//cout<<tmp<<endl;
f[i]=f[q[tmp]]-F[q[tmp]]*K+B;
while(h<t&&((f[q[t]]-f[q[t-]])*(F[i]-F[q[t]]))>=((f[i]-f[q[t]])*(F[q[t]]-F[q[t-]])))t--;
q[++t]=i;
}
put(f[n]);
return ;
}
要走的路还长。
dp的斜率优化的更多相关文章
- 【DP】斜率优化
斜率优化 入门题:PKU3709 很多人貌似都是做这道题来K斜率优化的,所以看了资料以后还是开始入手吧. 然而还是得跪求大神的程序啊 ORZ ORZ…… 其实理解斜率优化就是会列斜率不等式,还要理解剔 ...
- bzoj 1010 [HNOI2008]玩具装箱toy(DP的斜率优化)
1010: [HNOI2008]玩具装箱toy Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 7874 Solved: 3047[Submit][St ...
- 洛谷P3195 [HNOI2008] 玩具装箱 [DP,斜率优化,单调队列优化]
题目传送门 题目描述 P教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京.他使用自己的压缩器进行压缩,其可以将任意物品变成一堆,再放到一种特殊的一维容器中.P教授有编号为1...N ...
- 【HDOJ5956】The Elder(树形DP,斜率优化)
题意:有一棵n个点的有根树,每条边上有一个边权.给定P,从i跳到它的祖先j的费用是距离的平方+P,问所有点中到根节点1的总花费最大值 n<=1e5,p<=1e6,w<=1e2 思路: ...
- CF1179D Fedor Runs for President [DP,斜率优化]
Codeforces 思路 考虑把连的那两个点中间的链提出来,那么就会变成一条链,链上的每个点挂着一棵子树的形式. 设那些子树的大小为\(S_1,S2,\cdots\),那么新加的简单路径个数就是 \ ...
- dp之斜率优化
前几天想练练思维,所以从cf上随便找了一道dp题,看完题意后第一感觉很简单,就是简单的区间dp题,但是看到数据范围的我顿时就懵了,(1≤n≤105) emmmmmmmm,按照普通的思路肯定会超时的.. ...
- 【DP】斜率优化初步
向y总学习了斜率优化,写下这篇blog加深一下理解. 模板题:https://www.acwing.com/problem/content/303/ 分析 因为本篇的重点在于斜率优化,故在此给出状态转 ...
- [bzoj1492][NOI2007]Cash[CDQ分治;dp;斜率优化]
首先,设f[x]表示x天能获得的A券最大值,有动规方程: $f[i]=max\{f[j]*A[i]+f[j]*B[i]/R[j]\}*R[i]/(R[i]*A[i]+B[i])$, 设 $j<k ...
- CF932F Escape Through Leaf(DP,斜率优化)
SB 题. 写出 DP 方程:\(f_i\) 表示从 \(i\) 跳的最小值. \(i\) 是叶子就是 \(0\),否则就是选个子树中的 \(v\),\(f_i=\min(f_v+a_ib_v)\). ...
随机推荐
- 图灵数学·统计学丛书.PDF(53本全)
图灵数学·统计学丛书01-概率论及其应用(第1卷·第3版)-[美]William.Feller-人民邮电出版社.pdf 图灵数学·统计学丛书01-金融数学:衍生产品定价引论-[英]M·巴克斯特& ...
- 还原Stack操作
下午看到一题.给定两个int[]数组,int[] org和int[] res, 分别代表一串数字,和这串数字经过stack的push 和 pop操作之后的数字,让返回一个String, String里 ...
- 有趣的JavaScript原生数组函数
本文由 伯乐在线 - yanhaijing 翻译.未经许可,禁止转载!英文出处:flippinawesome.欢迎加入翻译小组. 在JavaScript中,可以通过两种方式创建数组,Array构造函数 ...
- (实用)pip源
Pypi官方源网站的连接速度实在慢点出奇,可以更换为豆瓣的源 vim ~/.pip/pip.conf 添加如下内容即可: [global]index-url=http://pypi.doubam.co ...
- classifier in maven
http://maven.apache.org/plugins/maven-deploy-plugin/examples/deploying-with-classifiers.html Beside ...
- MangoDB学习笔记
01. 数据库操作 1. 查看当前数据库名称 db 2. 查看所有数据库名称,列出所有在物理上存在的数据库 show dbs; 3. 切换数据库,如果数据库不存在也并不创建,直到插入数据或创建集合时数 ...
- Linux内核 设备树操作常用API
Linux设备树语法详解一文中介绍了设备树的语法,这里主要介绍内核中提供的操作设备树的API,这些API通常都在"include/of.h"中声明. device_node 内核中 ...
- 6.13 py网络编程
tcp的十种状态 python使用原始套接字才可以做黑客攻击!!!!!伪造数据包!!!!!直接越过底层!socket这个东西是经过linux过滤过得! TTL 每经过一个路由器就减1 谁先调clos ...
- TP5和TP3.2的区别
1.控制器输出 return $this->fetch("index/hello"); $this->display 单字母函数去掉了 如:M() D() U() S( ...
- 170830、oracle密码过期ORA-28002: 7天之后口令将过期的解决方法
登陆oracle数据库时错误信息提示:“ORA-28002: 7 天之后口令将过期”. 原因:oracle11g中默认在default概要文件中设置了"PASSWORD_LIFE_TIME= ...