879. 盈利计划

集团里有 n 名员工,他们可以完成各种各样的工作创造利润。

第 i 种工作会产生 profit[i] 的利润,它要求 group[i] 名成员共同参与。如果成员参与了其中一项工作,就不能参与另一项工作。

工作的任何至少产生 minProfit 利润的子集称为 盈利计划 。并且工作的成员总数最多为 n 。

有多少种计划可以选择?因为答案很大,所以 返回结果模 10^9 + 7 的值。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/profitable-schemes
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

动态规划

class Solution {

    private static final int MOD = 1000000007;

    public int profitableSchemes(int peoples, int minProfit, int[] group, int[] profit) {
        int groups = group.length;
        int[][][] dp = new int[groups + 1][peoples + 1][minProfit + 1];
        dp[0][0][0] = 1;
        for (int i = 1; i <= groups; ++i) {
            for (int j = 0; j <= peoples; ++j) {
                for (int k = 0; k <= minProfit; ++k) {
                    if (j >= group[i - 1]) {
                        dp[i][j][k] = (dp[i - 1][j][k] + dp[i - 1][j - group[i - 1]][Math.max(0, k - profit[i - 1])]) % MOD;
                    } else {
                        dp[i][j][k] = dp[i - 1][j][k];
                    }
                }
            }
        }
        int ans = 0;
        for (int j = 0; j <= peoples; ++j) {
            ans = (ans + dp[groups][j][minProfit]) % MOD;
        }
        return ans;
    }
}

动态规划 + 状态压缩

class Solution {

    private static final int MOD = 1000000007;

    public int profitableSchemes(int peoples, int minProfit, int[] group, int[] profit) {
        int groups = group.length;
        int[][] dp = new int[peoples + 1][minProfit + 1];
        for (int i = 0; i <= peoples; ++i) {
            dp[i][0] = 1;
        }
        for (int i = 1; i <= groups; ++i) {
            for (int j = peoples; j >= group[i - 1]; --j) {
                for (int k = minProfit; k >= 0; --k) {
                    dp[j][k] = (dp[j][k] + dp[j - group[i - 1]][Math.max(0, k - profit[i - 1])]) % MOD;
                }
            }
        }

        return dp[peoples][minProfit];
    }
}
posted @ 2022-01-26 16:43  Tianyiya  阅读(31)  评论(0)    收藏  举报