Milking Time
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 12324 Accepted: 5221
Description
Bessie is such a hard-working cow. In fact, she is so focused on maximizing her productivity that she decides to schedule her next N (1 ≤ N ≤ 1,000,000) hours (conveniently labeled 0..N-1) so that she produces as much milk as possible.
Farmer John has a list of M (1 ≤ M ≤ 1,000) possibly overlapping intervals in which he is available for milking. Each interval i has a starting hour (0 ≤ starting_houri ≤ N), an ending hour (starting_houri < ending_houri ≤ N), and a corresponding efficiency (1 ≤ efficiencyi ≤ 1,000,000) which indicates how many gallons of milk that he can get out of Bessie in that interval. Farmer John starts and stops milking at the beginning of the starting hour and ending hour, respectively. When being milked, Bessie must be milked through an entire interval.
Even Bessie has her limitations, though. After being milked during any interval, she must rest R (1 ≤ R ≤ N) hours before she can start milking again. Given Farmer Johns list of intervals, determine the maximum amount of milk that Bessie can produce in the N hours.
Input
- Line 1: Three space-separated integers: N, M, and R
- Lines 2..M+1: Line i+1 describes FJ’s ith milking interval withthree space-separated integers: starting_houri , ending_houri , and efficiencyi
Output
- Line 1: The maximum number of gallons of milk that Bessie can product in the N hours
Sample Input
12 4 2
1 2 8
10 12 19
3 6 24
7 10 31
Sample Output
43
解题心得:
- 题意就是有m头牛,每一只牛有一个产奶的时间段和一个奶量,Bessie可以去给每一头奶牛挤奶,但是每次给一个奶牛挤奶之后必须休息R分钟,问Bessie选择怎么挤奶可以使挤出的奶最多。
- 最直观的的方法还是记忆化搜索,不用去推状态转移方程式,直接跟着题意走就行了。但是如果要推状态转移方程式就有很多种方法了,看过其他大佬最简单的方法就是按照每一只牛的时间段来转移,dp[i]表示按开始产奶的时间顺序处理第i头牛可以获得的最大的产奶量,转移方程可以从前面j头牛(如果第j头牛的时间符合)+第i头牛产的奶来更新dp[i]的最大值。其实这个状态转移就讲记忆化搜索提炼出来的公式,具体的看代码吧。
记忆化搜索的代码:
#include <algorithm>
#include <cstring>
#include <stdio.h>
using namespace std;
const int maxn = 1010;
int n,m,R;
struct COW {
int l,r,va;
}cow[maxn];
long long dp[maxn*maxn];
bool cmp(COW a, COW b) {
return a.l < b.l;
}
void init() {
memset(dp,-1,sizeof(dp));
scanf("%d%d%d",&n,&m,&R);
for(int i=0;i<m;i++) {
scanf("%d%d%d",&cow[i].l,&cow[i].r,&cow[i].va);
}
sort(cow,cow+m,cmp);
}
long long dfs(int num,int Time) {
long long k0 = 0,k1 = 0;
if(num >= m || Time >= n)
return 0;
if(dp[Time] != -1 && Time != -1)
return dp[Time];
if(cow[num].l >= Time && cow[num].r <= n) { //如果时间符合那就加上当前这头牛的产奶量
k1 += dfs(num+1,cow[num].r+R) + cow[num].va;
} else
k1 += dfs(num+1,Time);//时间不符合直接检查下一头
k0 += dfs(num+1,Time);
return dp[Time] = max(k0,k1);
}
int main() {
init();
long long ans = dfs(0,-1);
printf("%lld\n",ans);
return 0;
}
提炼出状态转移的公式之后的代码:
#include <algorithm>
#include <stdio.h>
using namespace std;
const int maxn = 1010;
struct COW {
int start_time,end_time,va;
bool operator < (const COW &A) const {
return A.start_time > start_time;
}
}cow[maxn];
int dp[maxn];
int main() {
int n,m,R;
scanf("%d%d%d",&n,&m,&R);
for(int i=1;i<=m;i++) {
scanf("%d%d%d",&cow[i].start_time,&cow[i].end_time,&cow[i].va);
cow[i].end_time += R;//实际结束的时间 = 结束时间 + 休息时间
}
sort(cow+1,cow+m+1);
for(int i=1;i<=m;i++) {
dp[i] = cow[i].va;
for(int j=1;j<i;j++) {
if(cow[j].end_time <= cow[i].start_time)
dp[i] = max(dp[i],dp[j] + cow[i].va);
}
}
int ans = 0;
for(int i=0;i<=m;i++)
ans = max(ans,dp[i]);
printf("%d\n",ans);
return 0;
}