区间动态规划例题:带权重的字符串交织问题(最小化交织成本)
题目描述
给定三个字符串:A、B 和 C,以及一个成本函数 cost(i, j, k),其中 i、j、k 分别是 A、B、C 的索引。
字符串 C 的长度为 n + m(其中 n = len(A), m = len(B))。我们需要判断 C 是否可以通过交织 A 和 B 得到(保持 A 和 B 的字符顺序不变),并计算最小交织成本。
交织成本定义为:
当选择 A 的第 i 个字符匹配 C 的某个位置时,产生成本 cost(i, -1, k);
当选择 B 的第 j 个字符匹配 C 的某个位置时,产生成本 cost(-1, j, k)。
目标是使总成本最小。
解题思路
这是一个区间动态规划问题,因为 C 是 A 和 B 的交织,我们可以逐步匹配 C 的字符到 A 或 B 中。
状态定义:
dp[i][j] 表示用 A 的前 i 个字符和 B 的前 j 个字符,匹配到 C 的前 (i + j) 个字符时的最小成本。
状态转移:
- 如果
A[i-1] == C[i+j-1],那么可以从dp[i-1][j]转移过来,加上成本cost(i-1, -1, i+j-1)。 - 如果
B[j-1] == C[i+j-1],那么可以从dp[i][j-1]转移过来,加上成本cost(-1, j-1, i+j-1)。 - 如果两个条件都满足,取成本较小的转移。
初始化:
dp[0][0] = 0(空字符串匹配空字符串)。
第一行和第一列需要单独初始化,表示只用 A 或只用 B 匹配 C 的情况。
答案:
dp[n][m] 即为最小交织成本。如果无法交织,则设置为无穷大。
循序渐进讲解
步骤1:定义状态
我们定义 dp[i][j]:
i表示已经使用了A的前i个字符(0 ≤ i ≤ n)。j表示已经使用了B的前j个字符(0 ≤ j ≤ m)。dp[i][j]表示匹配到C的前(i+j)个字符时的最小成本。
注意:C 的长度为 n+m,所以只有当 i+j 与 C 的位置对应时才有意义。
步骤2:状态转移方程
对于 dp[i][j],我们考虑 C 的第 (i+j) 个字符(索引为 i+j-1)是从 A 还是从 B 来的:
-
如果
i > 0且A[i-1] == C[i+j-1]:
说明当前字符可以来自A的第i个字符。
那么,匹配到前(i+j)个字符的最小成本 =dp[i-1][j] + cost(i-1, -1, i+j-1)。 -
如果
j > 0且B[j-1] == C[i+j-1]:
说明当前字符可以来自B的第j个字符。
那么,匹配到前(i+j)个字符的最小成本 =dp[i][j-1] + cost(-1, j-1, i+j-1)。 -
如果两个条件都满足,取两者中的较小值。
如果都不满足,则dp[i][j] = INF(表示无法匹配)。
转移方程:
dp[i][j] = min(
(dp[i-1][j] + cost(i-1, -1, i+j-1)) if i>0 and A[i-1]==C[i+j-1] else INF,
(dp[i][j-1] + cost(-1, j-1, i+j-1)) if j>0 and B[j-1]==C[i+j-1] else INF
)
步骤3:初始化
dp[0][0] = 0:空字符串匹配空字符串,成本为0。- 初始化第一行
dp[0][j](只用B匹配C):
需要检查B的前j个字符是否依次等于C的前j个字符,并且累加成本。
如果有任何一个字符不匹配,则dp[0][j] = INF。 - 初始化第一列
dp[i][0](只用A匹配C):同理。
示例:
for j in range(1, m+1):
if B[j-1] == C[j-1]:
dp[0][j] = dp[0][j-1] + cost(-1, j-1, j-1)
else:
dp[0][j] = INF
类似地处理 dp[i][0]。
步骤4:填表计算
按 i 从 0 到 n,j 从 0 到 m 的顺序填表(注意 i 和 j 不能同时为0)。
对于每个 (i, j),根据状态转移方程计算。
步骤5:输出答案
如果 dp[n][m] 为无穷大,则表示无法交织得到 C;
否则,dp[n][m] 即为最小交织成本。
举例说明
假设:
A = "ab",B = "bc",C = "abbc"- 成本函数简化:每次匹配的成本为0(即只判断能否交织,不求最小成本)。
步骤:
- 初始化
dp[0][0]=0。 - 初始化第一行:
B的前1个字符"b"与C[0]='a'不匹配 →dp[0][1]=INF,后面都为INF。 - 初始化第一列:
A的前1个字符"a"与C[0]='a'匹配 →dp[1][0] = dp[0][0] + 0 = 0。
A的前2个字符"ab"与C[0..1]="ab"匹配 →dp[2][0] = dp[1][0] + 0 = 0。 - 计算
dp[1][1]:- 来自
A:A[0]='a'与C[1]='b'不匹配,不可行。 - 来自
B:B[0]='b'与C[1]='b'匹配,且dp[1][0]=0→ 成本0。
所以dp[1][1] = 0。
- 来自
- 继续计算直到
dp[2][2]:- 最终状态
dp[2][2]应为0,表示可以交织得到C。
- 最终状态
复杂度分析
- 时间复杂度:O(n × m),需要填充二维表格。
- 空间复杂度:O(n × m),可以使用滚动数组优化到 O(m) 或 O(n)。
关键点总结
- 状态设计:
dp[i][j]表示用A的前i个和B的前j个匹配C的前(i+j)个字符的最小成本。 - 转移条件:必须检查当前字符是否与
A或B的对应字符相等。 - 初始化:第一行和第一列需要单独处理,因为它们代表只用
A或只用B的情况。 - 答案:
dp[n][m]是否为无穷大判断可行性,否则为最小成本。
这样,我们就完成了带权重的字符串交织问题的动态规划解法。通过状态转移逐步匹配字符,并累加成本,最终得到最小交织成本。