LeetCode1751.最多可以参加的会议数目 II---动态规划题解

该博客讨论了一个与01背包问题相似的优化问题,即在给定最多能参加的会议数目k的情况下,如何从一系列会议中选择,使得获得的总价值最大化。博主通过动态规划的方法,对会议按结束时间排序,然后进行状态转移,计算在前i个会议中选择不超过j次的最大结果。在转移过程中,博主使用了贪心策略,确保了会议时间不冲突。最终,博主给出了完整的Java代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1751. 最多可以参加的会议数目 II

给你一个 events 数组,其中 events[i] = [startDayi, endDayi, valuei] ,表示第 i 个会议在 startDayi 天开始,第 endDayi 天结束,如果你参加这个会议,你能得到价值 valuei 。同时给你一个整数 k 表示你能参加的最多会议数目。

你同一时间只能参加一个会议。如果你选择参加某个会议,那么你必须 完整 地参加完这个会议。会议结束日期是包含在会议内的,也就是说你不能同时参加一个开始日期与另一个结束日期相同的两个会议。

请你返回能得到的会议价值 最大和

1235.规划兼职工作相似,在前一题的基础上,添加了最多能参加 k 个会议的要求。

题目要求:在参加不超过 k 次会议的前提下,选择会议,得到最大值。

这与 01 背包有些相似:求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。每个物品的状态只有两种:0,不选;1,选。

本题中,会议也只有两种状态:参加或不参加。

理解了题意,发现可能可以用 01 背包做,重点是判断会议能不能参加(物品能不能放入背包)。

然后进入 dp 常规步骤

1、状态定义 2、状态计算 3、初始化 4、确定遍历顺序

1.状态定义

与 01 背包相似

int[][] f = new int[n][k];

f[i][j] 表示在前 i 个会议中选择,不超过 j 次能获得的最大结果。

2.状态计算

设当前会议为 ev。

与背包问题不同,本题中两个会议之间存在先后关系。所以要进行排序,保证 f[i][j]能由前 i 个状态转移而来。按照结束时间 end 排序。

Arrays.sort(events,(x,y) -> {
    return x[1] - y[1];
});

对于状态 f[i][j],会议 ev 有两种状态:

1.不选 f[i][j] = f[i - 1][j]

2.选,在会议时间不冲突的前提下 ev.start > lastEv.endf[i][j] = f[?][j - 1] + ev.val

在选的过程中,枚举之前的状态,如果有两个选择 f[i0]f[i1] i1 > i0,分别表示在前 i0 个会议中选,在前 i1 个会议中选,f[i1] 一定是大于等于 f[i0]的,因为会议已经按结束时间排序,回看状态定义,f[i1]包含f[i0]

所以对于 f[i][j] 只需要逆向枚举 f[i - 1]f[1],找到第一个符合要求的状态 i,进行转移,即可获得最大值。

int last = 0;
for(int j = i - 1; j >= 1; j--){
    int[] jv = events[j - 1];
    if(jv[1] < st){
        last = j;
        break;
    }
}
for(int u = 1; u <= k; u++){
    f[i][u] = Math.max(f[i - 1][u],f[last][u - 1] + v);
} 

3.初始化

特判会议数 = 0,特判 k = 0。结果都是 0,不需要初始化。

4.确定遍历顺序

f[i][j]f[0...i][0...j]转移而来,所以i,j从小到大遍历

Java 代码

class Solution {
    public int maxValue(int[][] events, int k) { 
        int n = events.length;
        int[][] f = new int[n + 1][k + 1];
        Arrays.sort(events,(x,y) -> {
            return x[1] - y[1];
        });
        int res = 0;
        for(int i = 1; i <= n; i++){
            int[] cur = events[i - 1];
            int st = cur[0];
            int ed = cur[1];
            int v = cur[2];
            int last = 0;
            for(int j = i - 1; j >= 1; j--){
                int[] jv = events[j - 1];
                //贪心
                if(jv[1] < st){
                    last = j;
                    break;
                }
            }
            for(int u = 1; u <= k; u++){
                f[i][u] = Math.max(f[i - 1][u],f[last][u - 1] + v);
            }     
        }
        
        return f[n][k];
        
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值