Cion 勒索病毒的最大收益
问题描述
小S在处理一个被Cion病毒攻击的数据库时,需要对一个包含 0
和 1
的二进制字符串进行特定的操作,来赚取尽可能多的Cion币。规则如下:
- 使用 一个
0
替换子串00
,可以获得a
枚Cion币。 - 使用 一个
1
替换子串11
,可以获得b
枚Cion币。 - 删除一个
0
,需要支付c
枚Cion币。
限制条件:
- 连续两次操作的编号不能具有相同的奇偶性。
例如:若第一个操作是00
替换,操作编号是偶数,则下一次操作的编号必须是奇数。
目标是:在满足上述规则的情况下,最大化可以获得的Cion币总数。
算法分析
为了解决这个问题,采用了基于深度优先搜索(DFS)+动态规划(缓存)的策略。代码利用了Python中的 functools.lru_cache
对子问题结果进行缓存,从而避免重复计算。
以下是代码的分步解析及详细解释:
代码解析
主函数
python
复制代码
def solution(n, a, b, c, s):
final_s, res = dfs(s, -1, a, b, c)
print(final_s)
return res
-
参数说明:
n
:字符串的长度。a
:替换00
为0
时获得的Cion币数量。b
:替换11
为1
时获得的Cion币数量。c
:删除0
时需要支付的Cion币数量。s
:输入的01字符串。
-
逻辑:
- 调用
dfs
函数开始搜索,返回 最终操作后的字符串 和 最大Cion币收益。 - 打印操作完成后的字符串,用于观察变化过程。
- 调用
深度优先搜索函数
@lru_cache(maxsize=None)
def dfs(s, flag, a, b, c):
res = 0 # 当前最大收益
final_s = s # 记录当前最优路径的字符串状态
-
@lru_cache(maxsize=None)
:- 使用 缓存机制 记录已经计算过的
s
和flag
状态。 - 防止对相同状态的重复计算,提高效率。
- 使用 缓存机制 记录已经计算过的
-
变量初始化:
res
:当前状态下的最大Cion币收益。final_s
:当前状态下的最终字符串。
操作1:替换 00
为 0
if i < len(s)-1 and s[i] == '0' and s[i+1] == '0' and flag != 1:
ss, result = dfs(s[:i]+s[i+1:], 1, a, b, c)
if res < result + a:
final_s, res = ss, result + a
-
条件检查:
s[i] == '0' and s[i+1] == '0'
:当前位置及下一个字符是连续的00
。flag != 1
:上一次操作的编号不能是奇数。
-
操作逻辑:
- 使用深度优先搜索处理新字符串
s[:i] + s[i+1:]
,即去掉一个0
。 - 操作后将收益增加
a
。
- 使用深度优先搜索处理新字符串
-
结果更新:
- 如果操作后的总收益
result + a
大于当前最大值res
,更新res
和final_s
。
- 如果操作后的总收益
操作2:替换 11
为 1
elif i < len(s)-1 and s[i] == '1' and s[i+1] == '1' and flag != 2:
ss, result = dfs(s[:i]+s[i+1:], 2, a, b, c)
if res < result + b:
final_s, res = ss, result + b
-
条件检查:
s[i] == '1' and s[i+1] == '1'
:当前位置及下一个字符是连续的11
。flag != 2
:上一次操作的编号不能是偶数。
-
操作逻辑:
- 使用深度优先搜索处理新字符串
s[:i] + s[i+1:]
,即去掉一个1
。 - 操作后将收益增加
b
。
- 使用深度优先搜索处理新字符串
-
结果更新:
- 如果操作后的总收益
result + b
大于当前最大值res
,更新res
和final_s
。
- 如果操作后的总收益
操作3:删除 0
elif s[i] == '0' and flag != 1:
ss, result = dfs(s[:i]+s[i+1:], 1, a, b, c)
if res < result - c:
final_s, res = ss, result - c
-
条件检查:
s[i] == '0'
:当前字符为0
。flag != 1
:上一次操作的编号不能是奇数。
-
操作逻辑:
- 使用深度优先搜索处理新字符串
s[:i] + s[i+1:]
,即删除一个0
。 - 操作后收益减少
c
。
- 使用深度优先搜索处理新字符串
-
结果更新:
- 如果操作后的总收益
result - c
大于当前最大值res
,更新res
和final_s
。
- 如果操作后的总收益
返回结果
return final_s, res
返回操作后的字符串和当前最大收益。
代码:
python实现代码如下:
from functools import lru_cache
@lru_cache(maxsize = None)
def dfs(s,flag,a,b,c):
res = 0
final_s = s
for i in range(len(s)):
if i < len(s)-1 and s[i] == '1' and s[i+1] == '1' and flag != 2:
ss,result = dfs(s[:i]+s[i+1:],2,a,b,c)
if res < result+b:
final_s,res = ss,result+b
elif i < len(s)-1 and s[i] == '0' and s[i+1] == '0' and 1!=flag:
ss,result = dfs(s[:i]+s[i+1:],1,a,b,c)
if res < result+a:
final_s,res = ss,result+a
elif s[i] == '0' and 1 != flag:
ss,result = dfs(s[:i]+s[i+1:],1,a,b,c)
if res < result-c:
final_s,res = ss,result-c
return final_s,res
def solution(n, a, b, c, s):
# Please write your code here
final_s,res = dfs(s,-1,a,b,c)
print(final_s)
return res
if __name__ == "__main__":
# You can add more test cases here
print(solution(5, 2, 2, 1, "01101") == 3 )
print(solution(6, 4, 3, 5, "110001") == 11 )
print(solution(6, 3, 2, 1, "011110") == 4 )
复杂度分析
-
时间复杂度:
- 每个状态
s
被缓存后仅访问一次,最多有2^n
个可能的状态。 - 每次递归中,最多遍历
len(s)
次,因此时间复杂度为O(n * 2^n)
。
- 每个状态
-
空间复杂度:
- 缓存使用
lru_cache
,需要额外的空间存储子问题解,空间复杂度为O(2^n)
。
- 缓存使用
测试样例解析
样例1
-
输入:
n = 5, a = 2, b = 2, c = 1, s = "01101"
-
输出:
3
-
操作顺序:
- 替换
00
为0
,获得 2。 - 删除一个
0
,支付 1。
- 替换
样例2
-
输入:
n = 6, a = 4, b = 3, c = 5, s = "110001"
-
输出:
11
-
操作顺序:
- 替换
11
为1
,获得 3。 - 替换
00
为0
,获得 4。 - 替换
00
为0
,获得 4。
- 替换
总结
- 此算法通过深度优先搜索和缓存技术有效解决了复杂的操作序列问题。
- 在规则的限制下,最大化Cion币收益的计算变得可行且高效。