DP动态规划

import sys
input = sys.stdin.readline().strip
# sys.stdin.readline() 读取的数据末尾可能会包含换行符,用strip()去掉
sys.setrecursionlimit(100000)
from functools import lru_cache
@lru_cache(maxsize=None)
def dfs(x):
    if x == 0 or x== 1:
        return 1
    return dfs(x-1)+dfs(x-2)

'''list.sort(key = lambda x:x[1] ) 
    input = sys.stdin.readline().strip
    # sys.stdin.readline() 读取的数据末尾可能会包含换行符,用strip()去掉
    n = list(map(int,input().split()))
    print(' '.join(map(str,a)))
    print(objects,sep='',end='\n')
    上取整  x/y   = (x+y-1)//y      math.ceil(x/2) = (x+1)/2
    bin(x) oct(x) int(x,y) y:x是几进制数,默认10   hex(x)    
    #字符串
    s.lower()  将字符串中的所有大写字母转换为小写字母。
    s.upper()  字符串中的小写字母转为大写字母。
    s.isalpha()  检查字符串是否全由字母组成
    s.isdigit()   用于检测字符串是否只包含数字字符
    #列表 list1.insert(插入位置,插入对象)  ;   list1.pop(指定位置)   ; list1.remove(删除对象) ; list.count(" ") ;   
    # 字典 dict1.get(a,'x') #有a则输出a的value,否则输出x
'''
''' datetime
    import datetime
    a=datetime.date(2024,3,4)
    b=datetime.date(2024,1,1)
    print(a-b)
    #输出:63 days, 0:00:00
    a.weekday()   #返回0-6,0是星期一
    from datetime import datetime,timedelta
    #这里面常用的就是求两个日期中间隔了多少天
    l = datetime(2000,1,1)
    r = datetime(2020,10,1)
    r - l # 默认的是显示天数,可以通过timedelta进行修改
    #以及两个日期中间有多少个星期几什么的;直接遍历
    delta = timedelta(days=1)
    while l != r:
    l += delta
'''
'''heapq
    import heapq
    a = [11,6,9,8,7,3]
    heapq.heapify(a)
    print(a)            #[3, 6, 9, 8, 7, 11]
    heapq.heappush(a,5)
    print(a)           #[3, 6, 5, 8, 7, 11, 9]
    min=heapq.heappop(a)
    print(min,a)        #3 [5, 6, 9, 8, 7, 11]
    heapq.heapreplace(a,4)
    print(a)          #[4, 6, 9, 8, 7, 11]
'''
'''bisect
    from bisect import bisect_left, bisect_right
    a = [0, 0, 1, 2, 2, 3]
    # bisect_left返回如果将0插入a中,且维持数组顺序不变的条件下
    # 放在最左边的索引。说人话就是a中第一个>=target的数的索引
    index_1 = bisect_left(a, 0)
    # bisect_right说人话就是a中最后一个>=target的数的索引+1
    index_2 = bisect_right(a, 0) # 注意返回的是实际的加1!
    # 注意,可以添加查找范围,[start,end),左闭右开,不要将a变成a[start:end]引进去!拷贝会浪费大
    量的时间!!!
    index_1 = bisect_left(a, 0, start,end)
    index_2 = bisect_right(a, 0,start, end)
'''
'''
# 二维前缀和  sum[i][j] = sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+a[i][j]
#区间二维前缀和 sum[x1][y1] - sum[x2][y2] = sum[x2][y2]-sum[x1-1][y2]-sum[x2][y1-1]+sum[x1-1][y1-1]
# 二维差分 : 差分数组的前缀和=原数组,将前缀和式中sum替换a,a替换成diff
# 双指针: l,r从左右同时开始向中间扫描
'''
'''二分答案
    def check(x):
        #判断x是否合法,合法返回True,否则返回False
        pass
    l,r ,ans=  #初始化
    while l<=r:
        mid = (l+r)/2
        if check(mid):
            ans = mid
            l = mid + 1
        else:
            r = mid - 1
    print(ans) 
'''
'''位运算 (将数字看作二进制去操作的)
    & 与运算:有0为0,全1为1
    | 或运算:有1为1,全0为0
    ^ 异或运算:相同为0,不同为1
    ~ 取反: 1变成0,0变成1    
'''
'''
    DFS(u): 1.对u打标记 2.对每个和u相邻的点v:if v未标记:DFS(v)
bfs:from collections import deque
    def bfs(s,t):       #s: 起点,t: 终点
        dis = [-1]*100001
        queue = deque()
        #1、将起点塞入到队列中,打上标记
        queue.append(s)
        dis[s] = 0
        #2、当队列非空
        while len(queue) != 0:
            # 2.1 取出队首元素u
            u = queue.popleft()
            #2.2 判断u是否为终点
            if u == t:
                return dis[u]
            #2.3 将u相连的所有点v,只要v未标记,则入队列
            for v in [u-1,u+1,u*2]:
                #特判:未越界、未标记
                if 0<=v<=100000 and dis[v] == -1:
                    queue.append(v)
                    dis[v] = dis[u] + 1
        return -1
    n,k = map(int,input().split())
    print(bfs(n,k))
'''
'''dp
    dp[i][j] = max(dp[i-1][j],dp[i-1][j-w]+v) #01
    dp[i][j] = max(dp[i-1][j],dp[i][j-w]+v)   #完全
    for k in range(min(s,j//w)+1):
        dp[i][j] = max(dp[i][j],dp[i-1][j-k*w]+k*v) #多重
    if j<w: dp[i][j] = max(dp[i][j],dp[i-1][j])  #分组
    else: dp[i][j] = max(dp[i][j],dp[i-1][j],dp[i-1][j-w]+v) 
'''

01dp背包与魔法 2223

n,m,k = map(int,input().split())
wv = [[0,0]]
for i in range(n):
  wi,vi = map(int,input().split())
  wv.append([wi,vi])
dp = [[0]*2 for j in range(m+1)]
# dp[i][0]   不使用魔法i容量能装的最大价值,dp[i][1]使用魔法i容量能装的最大价值
for i in range(1,n+1):
  for j in range(m,wv[i][0]-1,-1):
    dp[j][0] = max(dp[j][0],dp[j-wv[i][0]][0]+wv[i][1])
    dp[j][1] = max(dp[j][1],dp[j-wv[i][0]][1]+wv[i][1])
    if j>=wv[i][0]+k:
      dp[j][1] = max(dp[j][1],dp[j-wv[i][0]-k][0]+2*wv[i][1])
print(max(dp[m][0],dp[m][1]))

01dp购物策略 3965

n = int(input())
a =[[0,0]]
max_t = 0
for i in range(1,n+1):
    t,c = map(int,input().split())
    t += 1
    a.append([t,c])
    max_t = max(max_t,t)
max_t += n
dp = [float('inf')] *(max_t+1)
# dp[i] 买i件商品的最少价值。    t看作体积,c看作价值。求最小价值
dp[0] = 0
for i in range(1,n+1):
    for j in range(max_t,a[i][0]-1,-1):
        dp[j] = min(dp[j],dp[j-a[i][0]]+a[i][1])
print(min(dp[n:]))

树形dp  最大独立集   1319

from collections import defaultdict
n = int(input())
a = [0] + list(map(int,input().split()))    #结点权值
edges = defaultdict(list)                   #结点关系
dp = [[0,a[i]]for i in range(n+1)]          #选或不选

for _ in range(n-1):                        #生成树
    u,v = map(int,input().split())
    edges[u].append(v)
    edges[v].append(u)

def dfs(u,fu):
    for v in edges[u]:
        if v == fu:
            continue
        dfs(v,u)
        dp[u][0] += max(dp[v][0],dp[v][1])
        dp[u][1] += dp[v][0]
dfs(1,0)
print(max(dp[1][0],dp[1][1]))

树形dp最小支配集

from collections import defaultdict
n = int(input())
edges = defaultdict(list)
a = [0] + list(map(int,input().split()))
dp = [[0,a[i]] for i in range(n+1) ]
for _ in range(n-1):
    u,v = map(int,input().split())
    edges[u].append(v)
    edges[v].append(u)
def dfs(u,fu):
    for v in edges[u]:
        if v == fu:
            continue
        dfs(v,u)
        dp[u][0] += dp[v][1]
        dp[u][1] += min(dp[v][0],dp[v][1])
dfs(1,0)
print(min(dp[1][0],dp[1][1]))

树形dp最小覆盖点

他要建立一个古城堡,城堡中的路形成一棵无根树。他要在这棵树的结点上放置最少数目的士兵,使得这些士兵能瞭望到所有的路。 注意,某个士兵在一个结点上时,与该结点相连的所有边将都可以被瞭望到。 请你编一程序,给定一树,帮 Bob 计算出他需要放置最少的士兵。

from collections import defaultdict
n = int(input())
edges = defaultdict(list)
dp = [[0,1] for i in range(n+1) ]
for _ in range(n-1):
    u,v = map(int,input().split())
    edges[u].append(v)
    edges[v].append(u)
def dfs(u,fu):
    for v in edges[u]:
        if v == fu:
            continue
        dfs(v,u)
        dp[u][0] += dp[v][1]
        dp[u][1] += min(dp[v][0],dp[v][1])
dfs(1,0)
print(min(dp[1][0],dp[1][1]))

换根dp

from collections import defaultdict
def dfs(u, dep, fa):  # 传入当前节点u,深度,父节点
    global sum_depth
    sum_depth += dep  # 加上当前节点u的深度
    # 遍历u的所有子节点
    for v in e[u]:
        if v == fa:
            continue
        dfs(v, dep + 1, u)  # 遍历到子节点
        siz[u] += siz[v]  # 通过这一步,可以统计u所有子节点数
def dfs2(u, fa):  # 用来跟新其余节点为根的解
    for v in e[u]:
        if v == fa:
            continue
        # dp[v] = dp[u] - siz[v] + (n - siz[v])
        dp[v] = dp[u] - 2 * siz[v] + n  # 当前节点v的解=左边变化值+右边变化值
        dfs2(v, u)
n = int(input())
dp = [0] * (n + 1)  # 用来更新不同节点为根时的深度和
siz = [1] * (n + 1)  # 以i为根节点,其左子树的节点数,初始值为1表示仅包含该节点
# 建树
e = defaultdict(list)
for _ in range(n - 1):
    u, v = map(int, input().split())
    e[u].append(v)
    e[v].append(u)
# 第一遍dfs,找到以1为根节点的深度和
sum_depth = 0  # 用来记录深度和
dfs(1, 0, 0)
# 第二遍dfs,求出其余点作为根的答案
dp[1] = sum_depth  # 6
dfs2(1, 0)  # dp=[0, 6, 5, 9, 8, 8]
print(max(dp))

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值