POJ 3616 Milking Time

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;
}

Accept 712K/32MS

你可能感兴趣的:(dp,ACM,poj,ICPC,区间问题)