題目描述:
幫派裏有 G 名成員,他們可能犯下各種各樣的罪行。第 i 種犯罪會產生 profit[i] 的利潤,它要求 group[i] 名成員共同參與。讓我們把這些犯罪的任何子集稱爲盈利計劃,該計劃至少產生 P 的利潤。有多少種方案可以選擇?因爲答案很大,所以返回它模 10^9 + 7 的值。
設dp[i][j][k]的含義爲前i個犯罪花費k個人達到至少j利潤的方案數,則有選做第i個犯罪還是不選:
dp[i][j][k] = dp[i-1][j][k] + dp[i-1][j-profit[i-1]][k-group[i-1]]
含義是不做第i個犯罪,那麼有dp[i-1][j][k]個方案;做第i個犯罪,有dp[i-1][j-profit[i-1]][k-group[i-1]]個方案。注意group和profit都是從下標0開始,所以爲i-1。
動態規劃很重要的一點是邊界問題。當利潤爲0時,無論i和k爲多少,dp[i][0][k]=1,表示只有一種方案(就是不做)。
代碼:
class Solution {
public:
int profitableSchemes(int G, int P, vector<int>& group, vector<int>& profit) {
const long Mod = 1e9 + 7;
int T = group.size();
vector<vector<vector<int>>> dp(T+1,vector<vector<int>>(P+1,vector<int>(G+1,0)));
// dp[0][0][0] = 1;
for (int i = 0;i<=T;i++){
for(int j = 0;j<=G;j++){
dp[i][0][j] = 1;
}
}
for (int t = 1;t<=T;++t){
int p = profit[t-1];
int g = group[t-1];
for(int i = 0;i<=P;++i){
for (int j = 0; j<=G;++j){
dp[t][i][j] = (dp[t-1][i][j] + (j<g ? 0: dp[t-1][max(0,i-p)][j-g]))%Mod;
}
}
}
return dp[T][P][G];
}
};
還有一些小細節需要注意,判斷利潤是否大於0,以及花費的人數是否大於第t個任務所需的人數。