题目
题目链接
解题思路
- 这是一个动态规划问题,需要求解所有和为 \(m\) 的不同整数组合个数
- 状态定义:
- \(dp[i][j]\) 表示使用 \(1\) 到 \(i\) 这些数字,凑成和为 \(j\) 的组合数
- 状态转移方程:
- 当 \(j \geq i\) 时:\(dp[i][j] = dp[i-1][j-i] + dp[i-1][j]\)
- 当 \(j < i\) 时:\(dp[i][j] = dp[i-1][j]\)
- 基础情况:
- \(dp[i][0] = 1\)(和为0的组合只有一种,即不选任何数)
代码
#include <iostream>
#include <vector>
using namespace std;int main() {int n, m;cin >> n >> m;// 创建dp数组并初始化vector<vector<int>> dp(n + 1, vector<int>(m + 1, 0));// 初始化和为0的情况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 >= i) {dp[i][j] = dp[i-1][j-i] + dp[i-1][j];} else {dp[i][j] = dp[i-1][j];}}}cout << dp[n][m];return 0;
}
import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner sc = new Scanner(System.in);int n = sc.nextInt();int m = sc.nextInt();// 创建dp数组并初始化int[][] dp = new int[n + 1][m + 1];// 初始化和为0的情况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 >= i) {dp[i][j] = dp[i-1][j-i] + dp[i-1][j];} else {dp[i][j] = dp[i-1][j];}}}System.out.println(dp[n][m]);}
}
def count_combinations(n, m):# 创建dp数组并初始化dp = [[0] * (m + 1) for _ in range(n + 1)]# 初始化和为0的情况for i in range(n + 1):dp[i][0] = 1# 动态规划填表for i in range(1, n + 1):for j in range(1, m + 1):if j >= i:dp[i][j] = dp[i-1][j-i] + dp[i-1][j]else:dp[i][j] = dp[i-1][j]return dp[n][m]n, m = map(int, input().split())
print(count_combinations(n, m))
算法及复杂度
- 算法:动态规划
- 时间复杂度:\(\mathcal{O}(n \cdot m)\) - 需要填充 \(n \cdot m\) 的dp数组
- 空间复杂度:\(\mathcal{O}(n \cdot m)\) - 需要一个 \(n \cdot m\) 的dp数组