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)\). ...
随机推荐
- git 命令常用总结
详细git教程可参考:http://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000 基础命令 用 ...
- cuda和显卡驱动版本
TensorFlow安装时需要cuda+对应的显卡驱动.这里给出英伟达官方的cuda和驱动的对应: 地址在这里 然后在这里可下载最新的显卡驱动(英伟达公版的驱动,程序员友好型) 最后说一下我的Tens ...
- [教程]-三种空格unicode(\u00A0,\u0020,\u3000)表示的区别
1.不间断空格\u00A0,主要用在office中,让一个单词在结尾处不会换行显示,快捷键ctrl+shift+space ; 2.半角空格(英文符号)\u0020,代码中常用的; 3.全角空格(中文 ...
- 【九天教您南方cass 9.1】 08 绘制等高线及对其处理
同学们大家好,欢迎收看由老王测量上班记出品的cass9.1视频课程 我是本节课主讲老师九天. 我们讲课的教程附件也是共享的,请注意索取测量空间中. [点击索取cass教程]5元立得 (给客服说暗号:“ ...
- Java知多少(84)图形界面之布局设计
在界面设计中,一个容器要放置许多组件,为了美观,为组件安排在容器中的位置,这就是布局设计.java.awt中定义了多种布局类,每种布局类对应一种布局的策略.常用的有以下布局类: FlowLayout, ...
- ABBYY PDF Transformer+系统要求
ABBYY PDF Transformer+是一个新的,全面的巧妙解决PDF文档的工具,它将泰比的光学字符识别(OCR)技术和Adobe®PDF技术完美结合,以确保实现便捷地处理任何类型的PDF文件, ...
- [Bayes] Improve HMM step by step
以下是HMM,当emission probability变为高斯时,只需改变其中相关部分即可,也就是下图最后一行. 如下可见,在优化过程中套路没有太大的影响,但变为高斯后表达变得更精确了呢. 当然,这 ...
- 删除新版UniAccess Agent 办公室监控软件的方法
UniAccess Agent 是在由LeagSoft开发的监控软件,老版本的一般安装在C:\Program Files\LeagSoft\UniAccess Agent这个目录下,一般找到这个目录点 ...
- Puppet报错汇总
报错1: 解决:该报错是由于Puppet agent 的时间和Puppet master的时间不一致导致,可以使用ntp同步一下时间即可解决 报错2: 启动mcollective的时候报错 解决:ge ...
- WP8.1学习系列(第二十七章)——ListView和GridView入门
快速入门:添加 ListView 和 GridView 控件 (XAML) 在本文中 先决条件 选择 ListView 或 GridView 将项添加到项集合 设置项目源 指定项目的外观 指定视图 ...