解题思路
这是一道动态规划题目,主要思路如下:
-
问题分析:
- 给定
个正整数和目标和
- 从数组中选择若干数字求和
- 不同位置的相同数字视为不同方案
- 求所有可能的方案数
- 给定
-
解决方案:
- 使用动态规划
表示和为
的方案数
- 对每个数字,更新所有可能的和
- 从大到小更新避免重复计算
-
实现细节:
- 处理数字大于
的情况
- 使用
long long
避免溢出 - 从后向前更新
数组
- 处理数字大于
代码
#include <iostream>
#include <vector>
using namespace std;
int main() {
long long n, sum;
cin >> n >> sum;
// 读入数组
vector<long long> a(n);
for(int i = 0; i < n; i++) {
cin >> a[i];
}
// dp[i]表示和为i的方案数
vector<long long> dp(sum + 1, 0);
// 遍历每个数字
for(int i = 0; i < n; i++) {
// 跳过大于sum的数字
if(a[i] > sum) continue;
// 从大到小更新dp数组
for(long long j = sum; j > 0; j--) {
if(dp[j] > 0 && j + a[i] <= sum) {
dp[j + a[i]] += dp[j];
}
}
// 单独使用当前数字
dp[a[i]]++;
}
cout << dp[sum] << endl;
return 0;
}
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int sum = sc.nextInt();
// 读入数组
long[] a = new long[n];
for(int i = 0; i < n; i++) {
a[i] = sc.nextLong();
}
// dp[i]表示和为i的方案数
long[] dp = new long[sum + 1];
// 遍历每个数字
for(int i = 0; i < n; i++) {
if(a[i] > sum) continue;
// 从大到小更新dp数组
for(int j = sum; j > 0; j--) {
if(dp[j] > 0 && j + a[i] <= sum) {
dp[(int)(j + a[i])] += dp[j];
}
}
dp[(int)a[i]]++;
}
System.out.println(dp[sum]);
}
}
def count_combinations(n: int, target: int, nums: list) -> int:
# dp[i]表示和为i的方案数
dp = [0] * (target + 1)
# 遍历每个数字
for num in nums:
if num > target:
continue
# 从大到小更新dp数组
for j in range(target, 0, -1):
if dp[j] > 0 and j + num <= target:
dp[j + num] += dp[j]
dp[num] += 1
return dp[target]
def main():
n, target = map(int, input().split())
nums = list(map(int, input().split()))
print(count_combinations(n, target, nums))
if __name__ == "__main__":
main()
算法及复杂度
- 算法:动态规划
- 时间复杂度:
-
为数组长度,
为目标和
- 空间复杂度:
-
数组空间