#P3076. 工作安排(100分)
          
                        
                                    
                      
        
              - 
          
          
                      1000ms
            
          
                      Tried: 160
            Accepted: 50
            Difficulty: 5
            
          
          
          
                       所属公司 : 
                              华为od
                                
            
                      
          
 
- 
                        算法标签>动态规划          
 
工作安排(100分)
题面描述
小塔每周上班都会拿到自己的工作清单,工作清单内包含 n 项工作,每项工作都有对应的耗时时间(单位 h)和报酬。工作的总报酬为所有已完成工作的报酬之和。请你帮小塔安排一下工作,保证小塔在指定的工作时间 T 内工作,且总报酬最大化。
思路
本题是一个典型的0-1 背包问题。我们需要在总耗时不超过 T 的情况下,选择若干工作使得总报酬最大化。
关键点分析:
- 状态定义:设 dp[j] 表示在总耗时不超过 j 小时的情况下,能够获得的最大报酬。
 - 状态转移:对于每一项工作 (ti,wi),我们可以选择是否完成这项工作。
- 如果选择完成,则有 dp[j]=max(dp[j],dp[j−ti]+wi)。
 - 如果不选择,则保持原来的 dp[j] 不变。
 
 - 初始化:dp[0]=0,表示在耗时为0的情况下,报酬为0。其他 dp[j] 可以初始化为0。
 - 遍历顺序:为了避免重复计算,我们需要从后向前遍历时间 j,确保每项工作只被选择一次。
 
代码分析
- 
输入处理:
- 使用 
ios::sync_with_stdio(false);和cin.tie(0);来加快输入速度,适用于大规模数据。 - 读取总工作时长 T 和工作数量 n。
 - 使用一个 
vector存储所有工作的耗时和报酬。 
 - 使用 
 - 
动态规划数组初始化:
- 创建一个大小为 T+1 的数组 
dp,初始化所有元素为0,表示在不同耗时下的最大报酬。 
 - 创建一个大小为 T+1 的数组 
 - 
动态规划状态转移:
- 对于每一项工作 (t,w),从总耗时 T 开始向下遍历到 t,更新 
dp[j]。 - 更新规则:
dp[j] = max(dp[j], dp[j - t] + w),即选择是否完成当前工作以获得更高的报酬。 
 - 对于每一项工作 (t,w),从总耗时 T 开始向下遍历到 t,更新 
 - 
结果计算:
- 遍历 
dp数组,找到最大的报酬值即为最终答案。 
 - 遍历 
 - 
时间优化:
- 使用一维数组进行状态压缩,减少内存占用。
 - 通过从后向前遍历,确保每项工作只被选择一次,避免重复计算。
 
 
cpp
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    int T, n;
    cin >> T >> n;
    vector<pair<int, int>> jobs(n);
    for(int i=0;i<n;i++) cin >> jobs[i].first >> jobs[i].second;
    // Initialize DP array
    vector<int> dp(T+1, 0);
    for(int i=0;i<n;i++){
        int t = jobs[i].first;
        int w = jobs[i].second;
        // Iterate from T downto t
        for(int j = T; j >= t; j--){
            if(dp[j - t] + w > dp[j]){
                dp[j] = dp[j - t] + w;
            }
        }
    }
    // Find the maximum reward
    int max_reward = 0;
    for(int j=0; j<=T; j++) max_reward = max(max_reward, dp[j]);
    cout << max_reward;
}
python
import sys
def main():
    import sys
    import sys
    # 读取输入
    T, n = map(int, sys.stdin.readline().split())
    jobs = []
    for _ in range(n):
        t, w = map(int, sys.stdin.readline().split())
        jobs.append((t, w))
    
    # 初始化DP数组
    dp = [0] * (T + 1)
    
    for t, w in jobs:
        # 从T倒序遍历到t,确保每项工作只被选择一次
        for j in range(T, t - 1, -1):
            if dp[j - t] + w > dp[j]:
                dp[j] = dp[j - t] + w
    
    # 找到最大的报酬
    max_reward = max(dp)
    print(max_reward)
if __name__ == "__main__":
    main()
java
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        
        int T = Integer.parseInt(st.nextToken());
        int n = Integer.parseInt(st.nextToken());
        
        int[] t = new int[n];
        int[] w = new int[n];
        
        for (int i = 0; i < n; i++) {
            st = new StringTokenizer(br.readLine());
            t[i] = Integer.parseInt(st.nextToken());
            w[i] = Integer.parseInt(st.nextToken());
        }
        
        // 初始化DP数组
        int[] dp = new int[T + 1];
        
        for (int i = 0; i < n; i++) {
            // 从T倒序遍历到t[i],确保每项工作只被选择一次
            for (int j = T; j >= t[i]; j--) {
                if (dp[j - t[i]] + w[i] > dp[j]) {
                    dp[j] = dp[j - t[i]] + w[i];
                }
            }
        }
        
        // 找到最大的报酬
        int maxReward = 0;
        for (int j = 0; j <= T; j++) {
            if (dp[j] > maxReward) {
                maxReward = dp[j];
            }
        }
        
        System.out.println(maxReward);
    }
}
        题目内容
小红每周上班都会拿到自己的工作清单,工作清单内包含 n 项工作,每项工作都有对应的耗时时间(单位 h)和报酬,工作的总报酬为所有已完成工作的报酬之和,那么请你帮小红安排一下工作,保证小红在指定的工作时间内工作收入最大化。
输入描述
输入的第一行为两个正整数 T,n。
- T 代表工作时长(单位 h, 0<T<1000),
 - n 代表工作数量( 1<n≤3000)。
 
接下来是 n 行,每行包含两个整数 t,w。
- t 代表该工作消耗的时长(单位 h, t>0),w 代表该项工作的报酬。
 
输出描述
输出小红指定工作时长内工作可获得的最大报酬。
样例1
输入
40 3
20 10
20 20
20 5
输出
30
说明