蓝桥杯备赛(九)-复杂DP

本文介绍了多个涉及动态规划的算法问题,包括鸣人的影分身、糖果分配、密码脱落、生命之树、斐波那契数列的前N项和、包子凑数和括号配对等,展示了不同类型的DP应用,如01背包、区间DP和树形DP,并给出了相应的解题代码。同时,提到了矩阵快速幂在解决斐波那契数列问题中的应用。

蓝桥杯备赛(九)-复杂DP

概念

DP问题,类似dfs的思想。

实例

Q1

鸣人的影分身(原题链接)

A1

dp[i][j]:总能量为i时,数量为j的组合总数。
dp[i][j]=dp[i][j-1]+dp[i-j][j]。
代码如下:

t=int(input())
for _ in range(t):
    m,n=map(int,input().split())
    f=[[0 for _ in range(11)] for _ in range(11)]
    f[0]=[1 for _ in range(11)]#初始化,当总和为0,个数为i时方案数为1
    for i in range(1,m+1):
        for j in range(1,n+1):
            f[i][j]=f[i][j-1]#有0的情况
            if (i-j)>=0:
                f[i][j]+=f[i-j][j]#没有的情况,则全部-1就就行
    print(f[m][n])

Q2

糖果(原题链接)

A2

很有趣的一道题目。01背包的变种。
代码如下:

n,k=map(int,input().split())
candy_lst=[0]
for _ in range(n):
    candy_lst.append(int(input()))
#构建初始dp数组
f=[[0 for _ in range(k)]for _ in range(n+1)]
f[1][(candy_lst[1])%k]=candy_lst[1]#初始化
for i in range(2,n+1):
    for j in range(k):
        num_1=f[i-1][j]
        num_2=f[i-1][(j+k-candy_lst[i])%k]+candy_lst[i] if f[i-1][(j+k-candy_lst[i])%k]!=0 else 0
        f[i][j]=max(num_1,num_2)
print(f[n][0])

Q3

密码脱落(原题链接)

A3

区间DP,利用双指针滑动进行求解。6
代码如下:

str_=list(input())
s=len(str_)
str_.extend([0 for _ in range(1001-len(str_))])
f=[[0 for _ in range(1001)]for _ in range(1001)]
for length in range(1,s+1):
    for i in range(1,s+1):
        #这里需要特判,如果j越界了将无意义
        if i+length-1>s:
            continue
        #为何采用此种遍历方式?避免出现未遍历便利用的情况
        j=i+length-1
        if i==j:
            f[i][j]=1
        else:
            #此处便看出了使用这种遍历的重要性
            if str_[i-1]==str_[j-1]:
                f[i][j]=f[i+1][j-1]+2
            else:
                f[i][j]=max(f[i+1][j],f[i][j-1])
print(s-f[1][s])

Q4

生命之树(原题链接)

A4

树型DP,首先构建树链表,然后采取遍历得到结果。
代码如下:

n=int(input())
happy=[0]
happy.extend(list(map(int,input().split())))
#创建初始字典,每个节点包含的value指的是该节点的连通区域
data={}
f=happy.copy()#记录每个节点联通区域最大值
for _ in range(n-1):
    a,b=map(int,input().split())
    if a in data:
        #若在
        data[a].append(b)
    else:
        data.setdefault(a,[b])
    if b in data:
        #若在
        data[b].append(a)
    else:
        data.setdefault(b,[a])
#构建成功,递归进行运算每个节点的最大值
def dfs(u,v):
    """
    u:表示当前节点(从1开始),v:表示其父节点(父节点无需遍历运算)
    """
    contact_lst=data[u]
    for i in contact_lst:
        if i!=v:
            #为子节点
            f[u]+=max(0,dfs(i,u))
    return f[u]
dfs(1,-1)
print(max(f[1:]))

Q5

斐波那契的前N项和(原题链接)

A5

矩阵快速幂+找规律
代码如下:

n,m=map(int,input().split())
def multi(a,b):
    """
    a:代表的是一个矩阵
    b:代表的是一个向量
    """
    temp=[0 for _ in range(len(b))]
    for i in range(len(a)):
        for j in range(len(b)):
            temp[i]+=a[i][j]*b[j]%m
        temp[i]%=m
    return temp

def _multi(a,b):
    """
    a:代表的是一个矩阵
    b:代表的是一个矩阵
    """
    temp=[[0 for _ in range(len(a[1]))]for _ in range(len(a))]
    for i in range(len(temp)):
        for j in range(len(temp[0])):
            for c in range(len(a[1])):
                temp[i][j]+=a[i][c]*b[c][j]%m
            temp[i][j]%=m
    return temp

#定义初始矩阵
res=[1,0,0]#才是s1
matrix=[[2,0,-1],[1,0,0],[0,1,0]]
#快速幂算法
n-=1
while n:
    if n&1:#是个奇数
        res=multi(matrix,res)
    matrix=_multi(matrix,matrix)
    n>>=1
print(res[0])

Q6

包子凑数(原题链接)

A6

当所有蒸笼的公因数不为1,则说明较大的不为其公因数的倍数的数无法被凑出,此时为无限多
当其公因数为1时,由数据范围可知,99100是小于1e4的,故我们可以dp到10000即可,观察其是否为true
该题可以看作完全背包问题
f[i][j]:当选取第i种包子时,容量为j是否成立(false:不成立,true:成立)
于是f[i][j]=f[i-1][j]|f[i-1][j-Ai]|f[i-1][j-2
Ai]|…|f[i-1][j-nAi]…此时需要满足不要越界
此时复杂度为n,这会导致整个复杂度上升至n^3。依据题意,我们可以简化
f[i][j-Ai]=f[i-1][j-Ai]|f[i-1][j-2
Ai]|…|f[i-1][j-n*Ai].故原状态转移方程可以简化为
f[i][j]=f[i-1][j]|f[i][j-Ai]
代码如下:

def gcd(a,b):
    if b==0:
        return a
    c=a%b
    if c==0:
        return b
    return gcd(b,c)

n=int(input())
f=[[False for _ in range(10010)]for _ in range(n+1)]
nod_lst=[0]
nod_lst.append(int(input()))
d=nod_lst[-1]
for _ in range(n-1):
    nod_lst.append(int(input()))
    d=gcd(nod_lst[-1],d)
if d!=1:
    print('INF')
else:
    f[0][0]=True
    for i in range(1,n+1):
        for j in range(10010):
            f[i][j]=f[i-1][j]
            if j>=nod_lst[i]:
                f[i][j]|=f[i][j-nod_lst[i]]#注意这里,j=0是可行的方案!!!
    res=0
    for i in range(1,10010):
        if not f[n][i]:
            res+=1
    print(res)

Q7

括号配对(原题链接)

A7

一道典型的区间DP问题,但是如何求解是个问题。
我们这个题和密码之树那个不太一样,多了一个性质,于是我们必须在状态划分多加考虑两边不同的情况
这题和密码脱落也有些不同,GBE有回文的性质 或者 有另外一种性质,
例如 , ([])均是GBE,因此需要对s[L] 和 s[R]不匹配的情况需要进一步划分,
划分方式和石子合并类似
f[l][r].init(0)
f[l][r]=f[l+1][r-1]+2 if match …1
f[l][r]=max(f[l][k]+f[k+1][r]) k:位于之间 …2
两个式子合并
代码如下:

str_=input()
length=len(str_)
def match(a,b):
    if a=='('and b==')':return True
    if a=='['and b==']':return True
    return False
f=[[0 for _ in range(101)]for _ in range(101)]
for i in range(1,length+1):
    for l in range(1,length+1):
        if l+i-1<=length:
            #这时才有右端点
            r=l+i-1
            if match(str_[l-1],str_[r-1]):
                f[l][r]=f[l+1][r-1]+2
            for k in range(l,r):
                f[l][r]=max(f[l][r],f[l][k]+f[k+1][r])
print(length-f[1][length])

Q8

旅游规划(原题链接)

A8

树形DP,但需要添加一点直径知识。
代码如下:

def dfs_d(node):
    if v[node]:
        return 
    v[node] = 1
    for i in g[node]:
        if v[i]:
            continue
        dfs_d(i)
        d = d1[i] + 1
        if d > d1[node]:
            d2[node] = d1[node]
            d1[node] = d
            p1[node] = i
        elif d > d2[node]:
            d2[node] = d
    global maxd
    maxd = max(maxd, d1[node] + d2[node])
def dfs_u(node):
    if v[node]:
        return 
    v[node] = 1
    for i in g[node]:
        if v[i]:
            continue
        up[i] = up[node] + 1;
        if p1[node] == i:
            up[i] = max(up[i], d2[node] + 1);
        else:
            up[i] = max(up[i], d1[node] + 1);
        dfs_u(i)
n = int(input())
g = [[] for i in range(n)]
d1 = [0 for i in range(n)]
d2 = [0 for i in range(n)]
up = [0 for i in range(n)]
p1 = [0 for i in range(n)]
v = [0 for i in range(n)]
maxd = 0
for i in range(n-1):
    a,b = (int(x) for x in input().split())
    g[a].append(b)
    g[b].append(a)
v = [0 for i in range(n)]
dfs_d(0)
v = [0 for i in range(n)]
dfs_u(0)
for i in range(n):
    tmp = [d1[i],d2[i],up[i]]
    tmp.sort()
    if tmp[1] + tmp[2] == maxd:
        print(i)

总结

难的一批。

内容概要:本研究聚焦于绿电直连型电氢氨园区的优化运行,提出一种集成绿色电力直接供给、电解水制氢及氢气合成氨工艺的综合能源系统架构。通过建立包含风光发电、电解槽、氨合成反应器、储氢罐、电网交互及多类型负荷在内的系统模型,综合考虑绿电直供优先、能量梯级利用与多能互补原则,构建以系统综合运行成本最小化为目标的优化调度模型。研究采用Matlab与Python工具进行算法求解和仿真分析,利用实际气象与负荷数据完成案例验证,评估了不同运行策略下系统的经济性、可再生能源消纳能力与碳减排效益,为新型电氢氨一体化园区的规划与运行提供了理论依据和技术支撑。; 适合人群:具一定电力系统、新能源或化工背景的研究生、科研人员及从事综合能源系统规划与优化工作的工程技术人员。; 使用场景及目标:①用于科研学习,理解电--氨多能转换系统的建模与优化方法;②为工业园区的低碳化、智能化改造提供技术参考与决策支持;③作为开发类似综合能源管理系统的理论基础。; 阅读建议:此资源包含完整的模型代码、数据与论文,使用者应结合代码仔细研读论文中的模型构建部分,重点关注目标函数与约束条件的设计逻辑,并尝试修改参数进行仿真,以深入掌握优化算法在实际系统中的应用。
内容概要:本文深入探讨了RS485通信协议在芯片行业自动化测试系统中的实际开发与应用,涵盖其关键概念、电气特性、通信机制及与Modbus RTU协议的结合使用。文章重点介绍了差分信号完整性设计、主从时序控制、CRC校验与重传机制等核心技术要点,并通过一个基于Python的完整代码实例,展示了如何实现RS485主站对探针台、自动分选机等芯片测试设的控制与数据采集。此外,还分析了RS485在晶圆探针台、ATE设集群和环境监控等典型场景的应用,并展望了其与工业以太网融合、智能化诊断、高速化及AI集成的发展趋势。; 适合人群:具一定嵌入式系统或工业通信基础,从事芯片测试、自动化设开发及相关领域的研发人员,尤其是工作1-3年希望提升现场总线应用能力的工程师。; 使用场景及目标:①理解RS485在高干扰芯片测试环境中稳定通信的设计原理;②掌握Modbus RTU协议在Python下的实现方法,用于实际控制探针台、Handler等设;③构建可靠的数据采集与设控制系统,支持CRC校验、异常处理和日志追踪;④为后续向高速通信和智能诊断系统升级提供技术储。; 阅读建议:此资源强调实战开发,建议结合硬件环境动手调试代码,重点关注线程锁、CRC计算、帧解析和超时控制等关键环节,在真实产线中验证通信稳定性,并利用日志系统进行故障分析与优化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值