题目链接
描述
贝茜就是这样一头勤劳的奶牛。事实上,她非常专注于最大限度地提高自己的工作效率,以至于她决定安排下一个N(1≤N≤1,000,000)小时产生尽可能多的乳汁。
农夫约翰有一个M(1≤M≤1,000)的列表,这些间隔可能重叠,他可以在其中挤奶。每个间隔 i 有一个开始小时 (0 ≤ starting_hour i ≤ N),一个结束小时 (starting_hour i < ending_hour i ≤ N) 和相应的效率 (1 ≤ efficiency i ≤ 1,000,000),这表明他在该间隔内可以从 Bessie 获得多少加仑牛奶。农夫 John 分别在开始时间和结束时间开始时开始和停止挤奶。挤奶时,必须将 Bessie 挤奶整个间隔。
不过,即使是贝茜也有她的局限性。在任何间隔期间挤奶后,她必须休息R(1≤R≤N)小时,然后才能再次开始挤奶。给定农夫约翰斯的间隔列表,确定贝茜在N小时内可以产生的最大牛奶量。
输入
- 第 1 行:三个空格分隔的整数:N、M 和 R
- 第 2 行-M+1行:i+1 行描述了第 i 个挤奶间隔,有三个空格分隔的整数:starting_hour i、ending_hour i 和 efficiency i
输出
- 第 1 行:Bessie 在 N 小时内可以生产的最大加仑牛奶数
示例输入
12 4 2
1 2 8
10 12 19
3 6 24
7 10 31
示例输出
43
这是一个赋权区间调度问题,需要用动态规划解决。首先用一个结构体存储每个区间的开始时间、结束时间和权值,然后将区间按照结束时间的升序排序。
设p(j)为与活动j相容且结束时间不晚于start j的结束时间最晚的任务,首先用循环找到每个活动的p(j)。
设OPT(j)为活动1,2……j对应的最优解,每一步有以下两种情况:
(1)最终最优解包含j,则OPT(j)=OPT(p(j))+vj,即j的前一个最晚相容解加上j的权值
(2)最终最优解不包含j,则OPT(j)=OPT(j-1)
由此可以得到动态规划的递推公式:
OPT(j)=0 j=0
OPT(j)= max(vj+OPT(p(j)),OPT(j-1)) j≠0
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<algorithm>
using namespace std;
struct interval{
int start;
int finish;
int eff;
};
bool cmp(interval a,interval b){
if(a.finish==b.finish) return a.start<b.start;
return a.finish<b.finish;
}
interval inter[1005];
int p[1005],ma[1005];
int main(){
int n,m,r,i,j;
cin>>n>>m>>r; //这里的n其实是用不到的,输入进来就行
for(i=1;i<=m;i++){
cin>>inter[i].start>>inter[i].finish>>inter[i].eff;
}
sort(inter+1,inter+1+m,cmp);
for(i=m;i>=1;i--){
for(j=m-1;j>=1;j--){
if(inter[j].finish+r<=inter[i].start){//注意这里奶牛每工作完一个时间段需要休息r小时,所以寻找p[i]时需要加上r
p[i]=j;
break;
}
}
if(j==0) p[i]=0;
}
ma[0]=0;
for(i=1;i<=m;i++){
ma[i]=max(ma[i-1],ma[p[i]]+inter[i].eff);
}
cout<<ma[m]<<endl;
return 0;
}