(1/2)三国游戏
a. 问题重述
X、Y、Z三个数都会经历不同程度的【增加】,问最多多少次【增加】才能使最大数大于其他两数之和。
b. 题型分析
结束条件是:让其中一个数变得相较其他两者之和都大;
为了达到这个条件,我们引入一个概念叫【贡献度】,即相对增长量(X的【贡献度】 = A-B-C)
所以能够达到结束条件的小条件是:其中一个数的贡献度尽可能大。
换言之,
这是一道经典的贪心类题目:
局部最优(贡献度尽可能大) -->> 全局最优(对应数最后比其他和更大)
而且这个推导关系似乎找不出反对的点,所以可以把这道题就看做贪心的题目来写!
c. 代码实现
# 输入元素
n = int(input())
A = list(map(int,input().split()))
B = list(map(int,input().split()))
C = list(map(int,input().split()))
def win(A,B,C):# 以A元素获胜为例
w = 0 #结束条件记录
contribute = [] # 每个时间对获胜的献祭值
for i in range(n):
contribute.append(A[i]-B[i]-C[i])
contribute.sort(reverse = True) # 贡献最多的事件先发生(局部最优思想)
for i in range(n):
w += contribute[i]
if w <= 0: # 只有w大于0的情况才符合题意
return (i) # 第i个使得小于0了,说明i-1还是大于零的,但是由于range是从0开始遍历的,故返回i就行
return n # 都不小于零说明n遍历完了
# 调用函数
result = max(win(A,B,C),win(B,C,A),win(C,B,A))
# 特殊情况
if result == 0:
print(-1)
else:
print(result)
(2/2)松散子序列
a. 问题重述
意思就是你要至少隔一个数取值,问取到的最大价值(a价值为1,z价值26)
举个例子,假如给的字符串是‘abcde’:
不能连续取,则最大取作“a”、“c”、“e”(第一个、第三个、第五个)
b. 题型分析
这是经典的打家劫舍类型题目(也是隔间偷钱,问偷得的最大价值),而打家劫舍问题是动态规划(Dynamic Programming)能解决的经典题目。
图1 动态规划能解决的题型
对于动态规划类型题目的解题思路,读者若是想有一个全面的把握我推荐去b站搜索“代码随想录”的动态规划部分,以下的分析思路也是按照模版所著。
对于动态规划的解题有五个步骤:
- 明确dp数组的定义
- 确定递推公式
- dp数组的初始化
- 了解遍历顺序
- 如有报错可通过打印dp数组来检查
对于本题我们按照上面的思路分析之:
- 一般都是问什么设什么,本题求的是最大价值,故有下标为“ i ”时的最大价值是“ dp[i] ”,请随时记住 dp[i] 的含义
- 因为是隔数取值,所以 dp[i] 只有两种情况:假如现在有3个数,要么取第一和第三个数,要么取第二个数。
dp[i] = max(value[i]+dp[i-2],dp[i-1])
- dp数组的初始化,因为取得是最大值,故初始化为0没有问题
- 从前往后取
- ..
c. 代码实现
# 字母转化为价值
def value(a):
return (ord(a)-96)
s = input()
# def + initiatize(初始化)
dp = [0] * (len(s)+1) # 多一个0防止越界
# sequence(遍历顺序) and formula(递推公式)
for i in range(len(s)):
dp[i] += max(dp[i-1],dp[i-2] + value(s[i]))
print(max(dp))
持续更新,评论区交流