POJ 3616题目大意如下:
又是FJ和他的牛,FJ给牛指定了产奶时间段,每个时间段内,牛在不停的产奶,当这个时间段完结后,牛需要R时间休息。给出M个时间段,和指定的间隔休息时间,以及每个产奶时间段产奶数量,求产奶的最大值。
终于自己AC了一个dp,但是还是wrong了两次(不细心,把M当成了R)。简单dp的基本就是写出状态转移方程,dp数组对应0到第j段产奶时间短的最末时间,表示整个区间,因此对于考虑的第i段,和第j段有如下关系:
如果指定区间和参考段没有时间重叠那么就有dp[i] = dp[j] + Seg[i].efficient
当然如果此值比dp[i]小,那就不更新,即有:dp[i] = max(dp[i], dp[j] + Seg[i].efficient)
可能会想,这样做会把某些区间和参考段重合的情况忽视了,但是这样更新的另一个原因是:这些重合区间是包含之前区间情况的,而且由于dp是对应一个个时间段,所以如果后面重叠时间段实际的情况是不重叠时间段的话,实际这种情况就是不重叠时间段(之前已经有了)
代码如下:
#include <iostream> #include <algorithm> #include <cstdio> #include <cstring> using namespace std; typedef long long int LL; const int maxn = 1000; struct Milking { int start, end; int efficent; }Seg[maxn + 3]; int N, M, R; LL dp[maxn + 3]; bool camp(const Milking& lhs, const Milking& rhs) { return lhs.start < rhs.start || (lhs.start == rhs.start && lhs.end < rhs.end); } void solve() { LL ans = 0; sort(Seg, Seg + M, camp); for (int i = 0; i < M; i++) dp[i] = Seg[i].efficent; for (int i = 0; i < M; i++) { for (int j = 0; j < i; j++) { if (Seg[j].end + R <= Seg[i].start) dp[i] = max(dp[i], dp[j] + Seg[i].efficent); } ans = dp[i] > ans ? dp[i] : ans; } printf("%lld\n", ans); } int main(int argc, const char * argv[]) { // insert code here... scanf("%d %d %d", &N, &M, &R); for (int i = 0; i < M; i++) scanf("%d %d %d", &Seg[i].start, &Seg[i].end, &Seg[i].efficent); solve(); return 0; }