问题描述
小F面临一个有趣的挑战:给定一个数组,她需要将数组中的数字分为两组。分组的目标是使得一组数字的和的个位数等于给定的 A,另一组数字的和的个位数等于给定的 B。除此之外,还有一种特殊情况允许其中一组为空,但剩余数字和的个位数必须等于 A 或 B。小F需要计算所有可能的划分方式。
例如,对于数组 [1, 1, 1] 和目标 A = 1,B = 2,可行的划分包括三种:每个 1 单独作为一组,其余两个 1 形成另一组。如果 A = 3,B = 5,当所有数字加和的个位数为 3 或 5 时,可以有一组为非空,另一组为空。
测试样例
样例1:
输入:
n = 3,A = 1,B = 2,array_a = [1, 1, 1]
输出:3
样例2:
输入:
n = 3,A = 3,B = 5,array_a = [1, 1, 1]
输出:1
样例3:
输入:
n = 2,A = 1,B = 1,array_a = [1, 1]
输出:2
样例4:
输入:
n = 5,A = 3,B = 7,array_a = [2, 3, 5, 7, 9]
输出:0
解题思路
先总体求和判断是哪种情况,然后套用0-1背包模板代码
0-1背包
0-1背包问题是一个经典的动态规划问题,它描述了这样一个场景:给定一组物品,每个物品都有一个重量和一个价值,确定在不超过背包容量限制的情况下,所装物品的最大价值。
问题定义
- 物品:有 个物品,每个物品 有一个重量 和一个价值 。
- 背包容量:背包可以承载的最大重量为 。
- 目标:选择一些物品装入背包,使得背包中物品的总价值最大,同时不超过背包的容量限制。
动态规划解法
-
定义状态:设 表示考虑前 个物品,背包容量为 时的最大价值。
-
状态转移方程:
-
如果不取第 个物品,则 。
-
如果取第 个物品(前提是 ),则
-
综合两种情况,状态转移方程为:
-
-
初始化: 对所有 ,因为没有物品时价值为。
-
计算顺序:按照 从 到 , 从 到 的顺序填充 表。
0-1背包模板
def knapsack(W, w, v):
n = len(w)
dp = [[0 for _ in range(W+1)] for _ in range(n+1)]
for i in range(1, n+1):
for j in range(W+1):
if j < w[i-1]:
dp[i][j] = dp[i-1][j]
else:
dp[i][j] = max(dp[i-1][j], dp[i-1][j-w[i-1]] + v[i-1])
return dp[n][W]
# 示例
W = 50 # 背包容量
w = [10, 20, 30] # 物品重量
v = [60, 100, 120] # 物品价值
print(knapsack(W, w, v)) # 输出最大价值
解题代码
def solution(n, A, B, array_a):
array_sum = 0
res = 0
for i in range(n):
array_a[i] = array_a[i] % 10
array_sum += array_a[i]
if array_sum % 10 == A or array_sum % 10 == B:
res += 1
if array_sum % 10 != (A + B) % 10:
return res
array_a.sort()
array_a.reverse()
dp = [0] * (10 * n + 1)
dp[0] = 1
for i in range(n):
for j in range(10 * n, 0, -1):
if j >= array_a[i]:
dp[j] += dp[j - array_a[i]]
for i in range(A, 10 * n + 1, 10):
res += dp[i]
return res