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)\). ...
随机推荐
- What-does-git-remote-and-origin-mean
https://www.quora.com/What-does-git-remote-and-origin-mean https://stackoverflow.com/questions/29235 ...
- c++默认参数函数注意事项
再有默认参数的函数中,一般我们都把默认参数放在声明处而不是定义处. 如果声明和定义都有默认参数,编译器将会报错. 调用含有默认实参的函数时,我们可以包含参数,也可以省略. 有默认参数的函数,我们可以不 ...
- 1. RNN神经网络模型原理
1. RNN神经网络模型原理 2. RNN神经网络模型的不同结构 3. RNN神经网络-LSTM模型结构 1. 前言 循环神经网络(recurrent neural network)源自于1982年由 ...
- [转]理解下DMA/NorFlash/DDR下的Burst是个什么概念
DMA传送不经过CPU的控制,假如硬盘的数据不能经过DMA控制器读到内存,那么每完成一次将硬盘的数据读出来,再存放到内存的操作,都要通过CPU运行几条读写指令来完成,这时CPU就做不了别的事了,如果有 ...
- Qt 密码框不可选中、复制、粘贴、无右键菜单等
在做用户登录.修改密码的时候,往往会用到密码框,其中一些功能要求与普通的输入框不同. 例如:不能选中.复制.粘贴.无右键菜单等功能,当然设置密码不可见是必须的! 一般的密码框:(默认 可以选中,复制, ...
- excel 2007 无法输入中文
解决方法: 1.32位系统:找到C:\Program Files\Common Files\Microsoft Shared\OFFICE12\Office Setup Controller,将这个文 ...
- Javascript--数组转换成字符串
定义和用法 toString() 方法可把数组转换为字符串,并返回结果. 语法 arrayObject.toString() 返回值 arrayObject 的字符串表示.返回值与没有参数的 join ...
- linq时间筛选以及list时间筛选
Linq的时间筛选 //写法一:正常 IEnumerable<x> xList = dbContext.xs.OrderByDescending(u => u.CreateTime) ...
- 【Spring】Spring中用到的设计模式
1.简单工厂 又叫静态工厂方法模式,不属于23种设计模式之一. 简单工厂模式的实质是由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类. Spring中的BeanFactory就是简单工厂模式的 ...
- 解决UEFI启动模式下无法使用U盘启动WIN7安装界面
问题场景 现在很多人都习惯使用U盘进行安装系统,主要是快捷方便.本文主要是讲解一下U盘在UEFI模式下无法启动Windows7安装界面的问题,可能很多人会说使用PE系统进行安装,但是因为我的主板只有独 ...