多重部分和问题
//多重部分和问题 int MultipartSum(int a[], int m[], int n, int k){ int dp[n + 1]; memset(dp, -1, sizeof(dp)); dp[0] = 0; for(int i = 0; i <= n; i++){ for(int j = 0; j <= k; j++){ if(dp[j] >= 0){ dp[j] = m[i]; }else if(j < a[i] || dp[j - a[i]] <= 0){ dp[j] = -1; }else{ dp[j] = dp[j - a[i]] - 1; } } } return dp[k]; }
划分数
//划分数 int PartitionNumber(int n, int m, int M){ int dp[n + 1][m + 1]; memset(dp, 0, sizeof(dp)); dp[0][0] = 1; for(int i = 0; i <= n; i++){ for(int j = 1; j <= m; j++){ if(i - j >= 0){ dp[i][j] = dp[i - j][j] + dp[i][j - 1]; }else{ dp[i][j] = dp[i][j - 1]; } } } return dp[n][m]; }
进一步,如果要求每个集合的数量大于一:
//正整数划分数 int PartitionNumber(int n, int m, int M){ int dp[n + 1][m + 1]; memset(dp, 0, sizeof(dp)); dp[0][0] = 1; for(int i = 1; i <= n; i++){ for(int j = 1; j <= m; j++){ if(i - j >= 0){ dp[i][j] = dp[i - j][j] + dp[i - 1][j - 1]; }else{ dp[i][j] = dp[i - 1][j - 1]; } } } return dp[n][m]; }
更进一步,如果要求每个集合的数量大于一且互异:
//互异划分数 int DistinctivePartitionNumber(int n, int m, int M){ int dp[m + 1][n + 1]; memset(dp, 0, sizeof(dp)); dp[0][0] = 1; for(int i = 1; i <= n; i++){ for(int j = 1; j <= m; j++){ if(i - j >= 0){ dp[i][j] = dp[i - j][j] + dp[i - j][j - 1]; } } } return dp[n][m]; }
多重集组合数问题
详见:
多重集组合数问题(动态规划)——炎泽汐 の Blog
文章目录[隐藏] 题目描述 解析 代码实现(C++) 题目描述 有 n 种物品,第 i 种物品有 a_i 个, […]
//多重集组合数问题 int MultipleSetCombinationNumber(int n, int m, int M, int a[]){ int dp[m + 1][n + 1]; memset(dp, 0, sizeof(dp)); for(int i = 0; i <= n; i++){ dp[i][0] = 1; } for(int i = 1; i <= n; i++){ for(int j = 1; j <= m; j++){ if(j - 1 - a[i - 1] >= 0){ //避免负数 dp[i][j] = (dp[i - 1][j] + dp[i][j - 1] - dp[i - 1][j - 1 - a[i - 1]] + M) % M; }else{ dp[i][j] = (dp[i - 1][j] + dp[i][j - 1]) % M; } } } return dp[n][m]; }