D 第一分段 区间dp

本文介绍了一个基于动态规划的任务调度算法实现,通过计算每个任务的时间前缀和与权值前缀和,来确定如何最小化总花费。讨论了如何通过分段减少未来任务的完成时间,并展示了具体的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在这里插入图片描述
注意取min dp初始化为INF 乘法用long long
完成时间进行分解 取前缀和形式
j-i 分段延时 则j-n都会延时 dp[0]必须初始化0

#include<bits/stdc++.h>
using namespace std;
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)

#define forn(i,n)  for(int i=0;i<n;i++)
#define rep(i,a,n) for(int i=a;i<=n;i++)
typedef long long ll;
const int maxn=5005;	//200堆 
const int INF=0x3f3f3f3f;
const ll inf=0x3f3f3f3f3f3f3f3f;


int n,s;
ll dp[5005];	//乘法ll 最小花费取min 初始化INF 
ll val[maxn],sum[maxn];//5e5
// val前缀和 原先时间的前缀和 
int main(){
	memset(dp,INF,sizeof dp);
	cin>>n>>s;
	int t,v;
	rep(i,1,n){
		cin>>t>>v;
		sum[i]=sum[i-1]+t;
		val[i]=val[i-1]+v;
	}
	dp[0]=0;
	for(int j=1;j<=n;j++){
		for(int i=j;i<=n;i++){	//j-i j=3 i=3
			dp[i]=min(dp[i],dp[j-1]+s*(val[n]-val[j-1])+sum[i]*(val[i]-val[j-1]));	//1-i分段花费 本次j=3~i=3 上次i肯定到2=j-1 
		}	//sum[i]代表无s延迟的t前缀和 
	}
	cout<<dp[n]<<endl;	//将1-n分段的最小花费 
	return 0;
}

先求出每个任务耗费时间的前缀和 sum 数组,每个任务的权值前缀和 val 数组。
假如从[j,i]进行了一次分段,那么[j,n]的所有任务的完成时间都会往后延 s,这会使得花费答
案增加 s * (val[n] - val[j-1])
而[j,i]中的任务完成时间均为 sum[i],即花费增加了 sum[i] * (val[i] - val[j-1])
也就是说对于每一次分段,我们同时算出了对之后花费增加的贡献和当前完成这一段任务的
花费。因为每次分段都计算了对之后的所有贡献,所以在分段时就不需要考虑之前分段次数
的影响了。(因为之前分段时已经算过贡献)
用 dp[i]表示完成了[1,i]所有任务,最小的总花费。(总花费指已经花费的+对未来花费的贡献)
即 dp[i] = min(dp[i], dp[j] + sum[i] * (val[i] - val[j-1]) + s * (val[n] - val[j-1]))
枚举当前位置 i,和上一次分段的位置 j 即可,复杂度 O(n²)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值