NCSTOJ 1044 搬砖 —— 动态规划

题目描述

Sam暑假找了个搬砖的活儿,每天12个小时内有1~8种转可以搬,每种的时间的工资都不一样(如搬第一种砖的时间为0时~4时,工资为5元,搬第二种砖的时间为2时~6时,工资为8元),每次搬砖必须搬完才能搬下一次转(即不可重叠,如上例中搬第一种砖就不能搬第二种转),请你帮Sam拿拿主意,怎样安排可以赚到最多的工资?

输入

输入包含八组(八种砖),每组包含三个整数:搬砖开始时间s1、结束时间s2与工资sal。(0 <= s1 < 11 , 0 < s2 <= 11 , 1 <= sal <= 10)。

输出

Sam12小时内最多可以赚到的工资。

样例输入

3 5 1
1 4 5
0 6 8
4 7 4
3 8 6
5 9 3
6 10 2
8 11 4

样例输出

13

提示

对于样例的解释:
选择工作1、工作4、工作8,可以赚到13元。

这道题三个要点。
  1. 使用数组dp[i]记录选择第1~第i个工作可以得到的最大工资。dp[8]是答案。
  2. 对所有工作排序。
  3. 使用数组pre[i]记录选择第[i]个工作时,之前最晚可以选择的工作。
动态转移方程:

dp[i]有两种情况:

  • 选:dp[i] = 工作[i]的工资 + dp[i-1]
  • 不选:dp[i] = dp[i-1]

即:dp[i] = max(bz[i].sal + dp[pre[i]], dp[i-1])

#include <bits/stdc++.h>
using namespace std;
const int N = 10;
struct BZ{
    int s1,s2,sal;
}bz[N];
bool cmp(const BZ a, const BZ b){
    return (a.s2 < b.s2 || (a.s2==b.s2 && a.s1 < b.s1));
}
int dp[N]; // dp[i]表示选择工作i时可以得到的最大工资
int pre[N];// pre[i]表示选择工作i时之前最早可以选择的工作

void find_pre(){
    for(int i=1; i<=8; ++i)
        for(int j=1; j<=8; ++j)
            if(bz[i].s1 >= bz[j].s2)
                pre[i] = j;
}

void dfs(){
    dp[0] = bz[0].sal;
    for(int i=1; i<=8; i++)
        dp[i] = max(bz[i].sal + dp[pre[i]], dp[i-1]);
}

int main(){
    for(int i=1; i<=8; ++i)
        scanf("%d%d%d",&bz[i].s1, &bz[i].s2, &bz[i].sal);
    sort(bz+1, bz+9, cmp);
    find_pre();
    dfs();
    cout << dp[8] <<endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/zhaohaibo_/article/details/81626950