斜率优化dp 笔记

2024-03-29 01:52
文章标签 dp 优化 笔记 斜率

本文主要是介绍斜率优化dp 笔记,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

任务安排1

有 N 个任务排成一个序列在一台机器上等待执行,它们的顺序不得改变。

机器会把这 N 个任务分成若干批,每一批包含连续的若干个任务。

从时刻 00 开始,任务被分批加工,执行第 i 个任务所需的时间是 Ti。

另外,在每批任务开始前,机器需要 S 的启动时间,故执行一批任务所需的时间是启动时间 S 加上每个任务所需时间之和。

一个任务执行后,将在机器中稍作等待,直至该批任务全部执行完毕。

也就是说,同一批任务将在同一时刻完成。

每个任务的费用是它的完成时刻乘以一个费用系数 Ci。

请为机器规划一个分组方案,使得总费用最小。

输入格式

第一行包含整数 N。

第二行包含整数 S。

接下来 N行每行有一对整数,分别为 Ti 和 Ci,表示第 i 个任务单独完成所需的时间 Ti 及其费用系数 Ci。

输出格式

输出一个整数,表示最小总费用。

数据范围

1≤N≤5000,
0≤S≤50,
1≤Ti,Ci≤100

输入样例:
5
1
1 3
3 2
4 3
2 3
1 4
输出样例:
153

 f[i]表示选好前i个任务的最小值

关键点在于把每次开始的S时间造成的全部后续影响加到当前这次的操作中,这样就不用考虑之前启动了几次机器了,取消了后效性

虽然过程中的f[1~n-1]的设计的值与状态设计不一定相同但f[n]一定是相同的 

#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define endl '\n'using namespace std;typedef pair<int, int> PII;
typedef long long ll;const int N = 5010;int n, S;
ll T[N], C[N], sum[N];
ll f[N];int main()
{IOScin >> n >> S;for(int i = 1; i <= n; i ++)cin >> T[i] >> C[i];for(int i = 1; i <= n; i ++){sum[i] = sum[i - 1] + C[i];T[i] += T[i - 1];}for(int i = 1; i <= n; i ++){f[i] = 2e18;for(int j = 1; j <= i; j ++)//[j, i]{//关键点在于把每次开始的S时间造成的全部后续影响加到当前这次的操作中//虽然过程中的f[1~n-1]的设计的值与状态设计不一定相同但f[n]一定是相同的 ll res = f[j - 1] + T[i] * (sum[i] - sum[j - 1]) + S * (sum[n] - sum[j - 1]);f[i] = min(f[i], res);}}cout << f[n];return 0;
}

任务安排2

有 N个任务排成一个序列在一台机器上等待执行,它们的顺序不得改变。

机器会把这 N 个任务分成若干批,每一批包含连续的若干个任务。

从时刻 0 开始,任务被分批加工,执行第 i 个任务所需的时间是 Ti。

另外,在每批任务开始前,机器需要 S 的启动时间,故执行一批任务所需的时间是启动时间 S 加上每个任务所需时间之和。

一个任务执行后,将在机器中稍作等待,直至该批任务全部执行完毕。

也就是说,同一批任务将在同一时刻完成。

每个任务的费用是它的完成时刻乘以一个费用系数 Ci。

请为机器规划一个分组方案,使得总费用最小。

输入格式

第一行包含整数 N。

第二行包含整数 S。

接下来 N 行每行有一对整数,分别为 Ti 和 Ci,表示第 i 个任务单独完成所需的时间 Ti 及其费用系数 Ci。

输出格式

输出一个整数,表示最小总费用。

数据范围

1≤N≤3×1e5,
1≤Ti,Ci≤512,
0≤S≤512

输入样例:
5
1
1 3
3 2
4 3
2 3
1 4
输出样例:
153

 除了数据范围其余和上一题一样

把j - 1看为 j可推出的公式:f[i]=f[j]+T[i]*(C[i]-C[j])+S*(C[n]-C[j])

可以发现当i固定时f[i]、C[i]、T[i]为定值,有两个未知量C[j]和f[j]

设f[j]为y,C[j]为x,整理一下式子

f[j]=(T[i] + S) * C[j] + f[i] - T[i]*C[i] - S*C[n]

约等于y = kx + b

可以发现截距b越小f[i]就越小,此时便来到了真正的斜率优化

找到下面最外围的凸包,找到第一个斜率大于k的那条边的左端点,此点就是在k斜率下到达y轴时最低的那个点(因为k>0° && k < 90°)

找这个凸包的办法:取出后两个点(x1,y1),(x2,y2)与当前点(x3,y3)比,如果第一个点和第二个点的斜率大于第一个点和第三个点的斜率就删掉最后一个点。循环往复。最后再加进这个点。

一般来说是用二分去找的

但这题还有点小性质,就是斜率k在不断变大,因此可以用类似双指针+单调队列的方式解决该问题(只是和单调队列很像)

任务安排3

有 N 个任务排成一个序列在一台机器上等待执行,它们的顺序不得改变。

机器会把这 N 个任务分成若干批,每一批包含连续的若干个任务。

从时刻 0 开始,任务被分批加工,执行第 i 个任务所需的时间是 Ti。

另外,在每批任务开始前,机器需要 S 的启动时间,故执行一批任务所需的时间是启动时间 S 加上每个任务所需时间之和。

一个任务执行后,将在机器中稍作等待,直至该批任务全部执行完毕。

也就是说,同一批任务将在同一时刻完成。

每个任务的费用是它的完成时刻乘以一个费用系数 Ci。

请为机器规划一个分组方案,使得总费用最小。

输入格式

第一行包含两个整数 N 和 S。

接下来 N 行每行有一对整数,分别为 Ti 和 Ci,表示第 i 个任务单独完成所需的时间 Ti 及其费用系数 Ci。

输出格式

输出一个整数,表示最小总费用。

数据范围

1≤N≤3×105,
0≤S,Ci≤512,
−512≤Ti≤512

输入样例:
5 1
1 3
3 2
4 3
2 3
1 4
输出样例:
153

这道题只能用二分了

过程会爆ll记得开int128

还有注意同一条线上的多个点只能存在最边缘的两个,中间的要全删掉

举个例子 

1、2两点都符合要求,但1更好,可能会错求成2

1、2两点都行,但要选1而不能选2

但我写的二分会找到最左边的点,所以不是这里的问题,思来想去与第二题还有一点不同,就是S和T下限从1变成了0,就会出现横坐标不变的情况,出现了斜率无限大的情况,所以出现了=的情况

类似的情况会出现,造成难以估量的bug,所以,凸包一定不要留线段中间的点!!!

#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define endl '\n'using namespace std;typedef pair<int, int> PII;
typedef long long ll;const int N = 300010;int n, S;
ll T[N], C[N];
ll f[N];
int q[N];int main()
{IOScin >> n >> S;for(int i = 1; i <= n; i ++)cin >> T[i] >> C[i];for(int i = 1; i <= n; i ++){C[i] += C[i - 1];T[i] += T[i - 1];}int hh = 0, tt = -1;q[++ tt] = 0;for(int i = 1; i <= n; i ++){int l = hh, r = tt;while(l < r){int mid = l + r >> 1;ll x1 = C[q[mid]], y1 = f[q[mid]];ll x2 = C[q[mid + 1]], y2 = f[q[mid + 1]];if(y2 - y1 >= (T[i] + S) * (x2 - x1))r = mid;else l = mid + 1;} int j = q[l];f[i] = f[j] + T[i] * (C[i] - C[j]) + S * (C[n] - C[j]);ll x3 = C[i], y3 = f[i];while(hh < tt){ll x1 = C[q[tt - 1]], y1 = f[q[tt - 1]];ll x2 = C[q[tt]], y2 = f[q[tt]];//注意一定是>= !!!!!!if((__int128)(y2 - y1) * (x3 - x1) >= (__int128)(y3 - y1) * (x2 - x1))tt --;else break;}q[++ tt] = i;}cout << f[n];return 0;
}

运输小猫

小 S 是农场主,他养了 M 只猫,雇了 P 位饲养员。

农场中有一条笔直的路,路边有 N 座山,从 1 到 N 编号。

第 i 座山与第 i−1 座山之间的距离为 Di。

饲养员都住在 1 号山。

有一天,猫出去玩。

第 i 只猫去 Hi 号山玩,玩到时刻 Ti 停止,然后在原地等饲养员来接。

饲养员们必须回收所有的猫。

每个饲养员沿着路从 1 号山走到 N 号山,把各座山上已经在等待的猫全部接走。

饲养员在路上行走需要时间,速度为 1 米/单位时间。

饲养员在每座山上接猫的时间可以忽略,可以携带的猫的数量为无穷大。

例如有两座相距为 1 的山,一只猫在 2 号山玩,玩到时刻 3 开始等待。

如果饲养员从 1 号山在时刻 2 或 3 出发,那么他可以接到猫,猫的等待时间为 0 或 1。

而如果他于时刻 1 出发,那么他将于时刻 2 经过 2 号山,不能接到当时仍在玩的猫。

你的任务是规划每个饲养员从 1 号山出发的时间,使得所有猫等待时间的总和尽量小。

饲养员出发的时间可以为负。

输入格式

第一行包含三个整数 N,M,P。

第二行包含 n−1 个整数,D2,D3,…,DN。

接下来 M 行,每行包含两个整数 Hi 和 Ti。

输出格式

输出一个整数,表示所有猫等待时间的总和的最小值。

数据范围

2≤N≤1e5,
1≤M≤1e5,
1≤P≤100,
1≤Di<1000,
1≤Hi≤N,
0≤Ti≤1e9

输入样例:
4 6 2
1 3 5
1 0
2 1
4 9
1 10
2 10
3 12
输出样例:
3

 

#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define endl '\n'using namespace std;typedef pair<int, int> PII;
typedef long long ll;const int N = 110, M = 100010;int n, m, p;
ll f[N][M];//前i个人,收回前j只猫
ll d[M], a[M];
int q[M];
ll sum[M];ll gety(int i, int k)
{return f[i - 1][k] + sum[k];
}int main()
{IOScin >> n >> m >> p;for(int i = 2; i <= n; i ++){cin >> d[i];d[i] += d[i - 1];}for(int i = 1; i <= m; i ++){int h, t;cin >> h >> t;a[i] = t - d[h];}sort(a + 1, a + 1 + m);for(int i = 1; i <= m; i ++)sum[i] = sum[i - 1] + a[i];memset(f, 0x3f, sizeof f);//排除i个人带回0只小猫的代价为0for(int i = 0; i <= p; i ++)f[i][0] = 0;//派出0个人只有可能带回0只小猫 即f[0][0] = 0;已被包含for(int i = 1; i <= p; i ++){int hh = 0, tt = -1;q[++ tt] = 0;for(int j = 1; j <= m; j ++){//先把斜率小于a[j]的去掉while(hh < tt && gety(i, q[hh + 1]) - gety(i, q[hh]) < a[j] * (q[hh + 1] - q[hh]))hh ++;int k = q[hh];f[i][j] = f[i - 1][k] - sum[j] + sum[k] + j * a[j] - k * a[j];ll x3 = j, y3 = gety(i, j);while(hh < tt){ll x1 = q[tt - 1], y1 = gety(i, q[tt - 1]);ll x2 = q[tt], y2 = gety(i, q[tt]);if((y2 - y1) * (x3 - x1) >= (y3 - y1) * (x2 - x1))tt --;else break;}q[++ tt] = j;}}cout << f[p][m];return 0;
}

这篇关于斜率优化dp 笔记的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/857291

相关文章

Deepseek使用指南与提问优化策略方式

《Deepseek使用指南与提问优化策略方式》本文介绍了DeepSeek语义搜索引擎的核心功能、集成方法及优化提问策略,通过自然语言处理和机器学习提供精准搜索结果,适用于智能客服、知识库检索等领域... 目录序言1. DeepSeek 概述2. DeepSeek 的集成与使用2.1 DeepSeek API

Tomcat高效部署与性能优化方式

《Tomcat高效部署与性能优化方式》本文介绍了如何高效部署Tomcat并进行性能优化,以确保Web应用的稳定运行和高效响应,高效部署包括环境准备、安装Tomcat、配置Tomcat、部署应用和启动T... 目录Tomcat高效部署与性能优化一、引言二、Tomcat高效部署三、Tomcat性能优化总结Tom

解读Redis秒杀优化方案(阻塞队列+基于Stream流的消息队列)

《解读Redis秒杀优化方案(阻塞队列+基于Stream流的消息队列)》该文章介绍了使用Redis的阻塞队列和Stream流的消息队列来优化秒杀系统的方案,通过将秒杀流程拆分为两条流水线,使用Redi... 目录Redis秒杀优化方案(阻塞队列+Stream流的消息队列)什么是消息队列?消费者组的工作方式每

Oracle查询优化之高效实现仅查询前10条记录的方法与实践

《Oracle查询优化之高效实现仅查询前10条记录的方法与实践》:本文主要介绍Oracle查询优化之高效实现仅查询前10条记录的相关资料,包括使用ROWNUM、ROW_NUMBER()函数、FET... 目录1. 使用 ROWNUM 查询2. 使用 ROW_NUMBER() 函数3. 使用 FETCH FI

C#使用HttpClient进行Post请求出现超时问题的解决及优化

《C#使用HttpClient进行Post请求出现超时问题的解决及优化》最近我的控制台程序发现有时候总是出现请求超时等问题,通常好几分钟最多只有3-4个请求,在使用apipost发现并发10个5分钟也... 目录优化结论单例HttpClient连接池耗尽和并发并发异步最终优化后优化结论我直接上优化结论吧,

Java内存泄漏问题的排查、优化与最佳实践

《Java内存泄漏问题的排查、优化与最佳实践》在Java开发中,内存泄漏是一个常见且令人头疼的问题,内存泄漏指的是程序在运行过程中,已经不再使用的对象没有被及时释放,从而导致内存占用不断增加,最终... 目录引言1. 什么是内存泄漏?常见的内存泄漏情况2. 如何排查 Java 中的内存泄漏?2.1 使用 J

MySQL不使用子查询的原因及优化案例

《MySQL不使用子查询的原因及优化案例》对于mysql,不推荐使用子查询,效率太差,执行子查询时,MYSQL需要创建临时表,查询完毕后再删除这些临时表,所以,子查询的速度会受到一定的影响,本文给大家... 目录不推荐使用子查询和JOIN的原因解决方案优化案例案例1:查询所有有库存的商品信息案例2:使用EX

MySQL中my.ini文件的基础配置和优化配置方式

《MySQL中my.ini文件的基础配置和优化配置方式》文章讨论了数据库异步同步的优化思路,包括三个主要方面:幂等性、时序和延迟,作者还分享了MySQL配置文件的优化经验,并鼓励读者提供支持... 目录mysql my.ini文件的配置和优化配置优化思路MySQL配置文件优化总结MySQL my.ini文件

正则表达式高级应用与性能优化记录

《正则表达式高级应用与性能优化记录》本文介绍了正则表达式的高级应用和性能优化技巧,包括文本拆分、合并、XML/HTML解析、数据分析、以及性能优化方法,通过这些技巧,可以更高效地利用正则表达式进行复杂... 目录第6章:正则表达式的高级应用6.1 模式匹配与文本处理6.1.1 文本拆分6.1.2 文本合并6

Vue3 的 shallowRef 和 shallowReactive:优化性能

大家对 Vue3 的 ref 和 reactive 都很熟悉,那么对 shallowRef 和 shallowReactive 是否了解呢? 在编程和数据结构中,“shallow”(浅层)通常指对数据结构的最外层进行操作,而不递归地处理其内部或嵌套的数据。这种处理方式关注的是数据结构的第一层属性或元素,而忽略更深层次的嵌套内容。 1. 浅层与深层的对比 1.1 浅层(Shallow) 定义