https://www.icourse163.org/learn/PKU-1001894005?tid=1450413466#/learn/content
程序设计与算法(二)算法基础
这里写目录标题
1163:The Triangle
# 1163:The Triangle
# http://bailian.openjudge.cn/practice/1163
n = int(input())
D = [[-1] * n for i in range(n)]
for i in range(0, n):
line = input().split()
j = 0
for l in line:
D[i][j] = int(l)
j += 1
maxSum = D[n - 1] # maxSum 指向第n行
for i in range(n - 2, -1, -1):
for j in range(0, i + 1):
maxSum[j] = max(maxSum[j], maxSum[j + 1]) + D[i][j]
print(maxSum[0])
2533:Longest Ordered Subsequence 最长上升子序列
# 2533:Longest Ordered Subsequence
# http://bailian.openjudge.cn/practice/2533
# 第一行是序列的长度N(1≤N≤1000)。
N = int(input())
# 第二行给出序列中的N个整数,这些整数的取值范围都是0~10000。
b = input().split()
for i in range(len(b)):
b[i] = int(b[i])
# MaxLen(k) = Max{MaxLen(i):1<i<k且ai<ak,且k≠1} + 1
# MaxLen(k) = 在ak左边、“终点”数值小于ak且长度最大的那个上升子序列的长度 + 1
# 因为ak左边任何“终点”小于ak的子序列,加上ak后就能形成一个更长的上升子序列
maxLen = [1] * N # 以第k个数为终点的 最长上升子序列的长度 maxLen[k]
for k in range(1, N):
tmp = 0 # 第k个数左边的 上升子序列的最大长度
for i in range(0, k): # 查看以第i个数为终点的 最长上升子序列
if b[i] < b[k]: # 如果 b[k]左边的b[i] < b[k],那么b[i]才可能和b[k]构成上升子序列
if tmp < maxLen[i]: # 如果 maxLen[i] > 当前记录的 tmp
tmp = maxLen[i]
maxLen[k] = tmp + 1
print(max(maxLen))
1458:Common Subsequence 最长公共子序列
# 1458:Common Subsequence
# http://bailian.openjudge.cn/practice/1458
def longestCommonSubsequence(str1, str2):
len1 = len(str1)
len2 = len(str2)
maxLen = [[0] * (len2+1) for _ in range(len1+1)]
for i in range(1, len1+1):
for j in range(1, len2+1):
if str1[i-1] == str2[j-1]:
maxLen[i][j] = maxLen[i - 1][j - 1] + 1
else:
maxLen[i][j] = max(maxLen[i - 1][j], maxLen[i][j - 1])
return maxLen[len1][len2]
import sys
while True:
line = sys.stdin.readline()
if not line:
break
str1, str2 = line.split()
print(longestCommonSubsequence(str1, str2))
主函数这样写也行
while True:
try:
line = input().split()
except EOFError:
break
str1 = line[0]
str2 = line[1]
print(longestCommonSubsequence(str1, str2))
2945:拦截导弹 求最长不上升子序列的长度
# 2945:拦截导弹 求最长不上升子序列的长度
# http://bailian.openjudge.cn/practice/2945/
# 第一行,输入雷达捕捉到的敌国导弹的数量k(k<=25),
k = int(input())
# 第二行,输入k个正整数,表示k枚导弹的高度,按来袭导弹的袭击时间顺序给出,以空格分隔。
a = input().split()
for i in range(k):
a[i] = int(a[i])
# lenlen[i]是 以a[i]为终点的 最长不上升子序列 的长度
# 子序列中的元素不一定在原序列中是连续的
lenlen = [1 for _ in range(k)]
for i in range(1, k): # [1,k-1]
for j in range(0, i): # [0,i-1]
if a[j] >= a[i]: # 如果 a[i] 前面的 a[j] >= a[i]
lenlen[i] = max(lenlen[i], lenlen[j] + 1)
print(max(lenlen))
1088:滑雪
# 1088:滑雪
# http://bailian.openjudge.cn/practice/1088
class Point:
def __init__(self, h, r, c):
self.h = h
self.r = r
self.c = c
def huaxue_renrenweiwo(point, field, L, R, C): # 人人为我
for i in range(1, R * C): # 每次循环求points[i]的L[r][c]
r = point[i].r
c = point[i].c
# L[r][c] = [r][c]周围四个点中(高度 < field[r][c] 且 L值最大的)那个点P的值 + 1
if (r > 0 and field[r][c] > field[r - 1][c]): # 如果上面的[r - 1][c]存在
L[r][c] = max(L[r][c], L[r - 1][c] + 1)
if (c > 0 and field[r][c] > field[r][c - 1]): # 如果左边的[r][c - 1]存在
L[r][c] = max(L[r][c], L[r][c - 1] + 1)
if (r < R - 1 and field[r][c] > field[r + 1][c]): # 如果下面的[r + 1][c]存在
L[r][c] = max(L[r][c], L[r + 1][c] + 1)
if (c < C - 1 and field[r][c] > field[r][c + 1]): # 如果右边的[r][c + 1]存在
L[r][c] = max(L[r][c], L[r][c + 1] + 1)
return max(max(row) for row in L)
def huaxue_woweirenren(point, field, L, R, C): # 我为人人
for i in range(0, R * C): # 每次循环求points[i]的L[r][c]
r = point[i].r
c = point[i].c
# 每次循环开始时,points[i]的L值是已经最终求出了的
# 若L[r][c]已计算出最终结果,则对于[r][c]周围比它高的点P,P的L值至少可以是L[r][c] +1。
# 若当前记下的P的L值 < L[r][c] +1,则应将其更新为L[r][c] +1。
if (r > 0 and field[r - 1][c] > field[r][c]): # 如果上面的[r - 1][c]存在
L[r - 1][c] = max(L[r - 1][c], L[r][c] + 1)
if (c > 0 and field[r][c - 1] > field[r][c]): # 如果左边的[r][c - 1]存在
L[r][c - 1] = max(L[r][c - 1], L[r][c] + 1)
if (r < R - 1 and field[r + 1][c] > field[r][c]): # 如果下面的[r + 1][c]存在
L[r + 1][c] = max(L[r + 1][c], L[r][c] + 1)
if (c < C - 1 and field[r][c + 1] > field[r][c]): # 如果右边的[r][c + 1]存在
L[r][c + 1] = max(L[r][c + 1], L[r][c] + 1)
return max(max(row) for row in L)
RC = input().split()
R = int(RC[0])
C = int(RC[1])
point = [0] * C * R # 用一维数组存储所有的点,以便排序处理
field = [[0] * C for _ in range(R)] # 高度矩阵
for i in range(0, R):
RC = input().split()
for j in range(0, C):
field[i][j] = int(RC[j])
point[i * C + j] = Point(int(RC[j]), i, j)
L = [[1] * C for _ in range(R)] # 从点(i,j)出发的最长滑行长度
import operator
point.sort(key=operator.attrgetter('h'))
# print(huaxue_renrenweiwo(point, field, L, R, C))
print(huaxue_woweirenren(point, field, L, R, C))
2755:神奇的口袋
# 2755:神奇的口袋
# http://bailian.openjudge.cn/practice/2755
def Ways_recursion(volume, k): # 从前k种物品中选择一些,凑成体积volume的做法数目 # 递归
if (volume == 0): # 如果体积 == 0,那么可以凑成体积volume
return 1
if (k <= 0): # 如果物品 == 0,那么不可以凑成体积volume
return 0
# 从前(k - 1)种物品中选择一些,凑成体积volume的做法数目 +
# 从前(k - 1)种物品中选择一些,凑成体积(volume - a[k])的做法数目
return Ways(volume, k - 1) + Ways(volume - a[k], k - 1)
def Ways_Dynamic_Programming(Total_volume, N, a): # 动态规划
# Ways[volume][k]表示从前k种物品里凑出体积volume的方法数
Ways = [[0] * (N + 1) for _ in range(Total_volume + 1)]
# 凑出体积0的方法数 = 1
Ways[0] = [1] * (N + 1)
for volume in range(1, Total_volume + 1): # 遍历体积[1,Total_volume]
for k in range(1, N + 1): # 遍历物品
Ways[volume][k] = Ways[volume][k - 1] # 从前k种物品里凑出体积volume的方法数
if (volume >= a[k]): # 如果剩余的体积 >= 第k个物品的体积
# 那么再 + 从前(k - 1)种物品里凑出体积(volume - a[k])的方法数
Ways[volume][k] += Ways[volume - a[k]][k - 1]
# 从前N种物品中选择一些,凑成体积Total_volume的做法数目
return Ways[Total_volume][N]
Total_volume = 40
# 输入的第一行是正整数n (1 <= n <= 20),表示不同的物品的数目。
N = int(input())
# 接下来的n行,每行有一个1到40之间的正整数,分别给出a1,a2……an的值。
a = [0] * (N + 1)
for i in range(1, N + 1):
a[i] = int(input())
# 从前N种物品中选择一些,凑成体积Total_volume的做法数目
# print(Ways_recursion(Total_volume, N))
print(Ways_Dynamic_Programming(Total_volume, N, a))
4131:Charm Bracelet 超时
# 4131:Charm Bracelet
# http://bailian.openjudge.cn/practice/4131
# 使用滚动数组的人人为我的动态规划程序
class Item:
def __init__(self, w, d):
self.w = w
self.d = d
NM = input().split()
num_item = int(NM[0]) # N种物品
Total_volume = int(NM[1]) # 容积为M
# 第二行到第N+1行:每行两个整数W和D,描述一个物品的体积和价值。
items = [0] * (num_item + 1)
for i in range(1, num_item + 1):
WD = input().split()
items[i] = Item(int(WD[0]), int(WD[1]))
# F(i,j)表示在前i种物品中取若干种,在其总体积不超过j的条件下能获得的最大价值
# 对f数组进行初始化,初始化结束后,f[j]的值就代表在前一种物品中选取,总体积不能超过j,
# 此时所能获得的最大价值即前述F(1,j)。
f = [0] * (Total_volume + 1)
for j in range(0, Total_volume + 1): # 在前i=1种物品中取若干种
if items[1].w <= j: # 若第1种物品的体积 <= j,则必取之,F(1,j)值为D[1]
f[j] = items[1].d
else:
f[j] = 0 # 若第1种物品的体积 > j,则不能取,F(1,j)值为0
for i in range(2, num_item + 1): # i代表从前i种物品中选取
for j in range(Total_volume, -1, -1): # j表示总体积不能超过j,从右到左计算f的值
if items[i].w <= j:
# f[i][j] = max(f[i - 1][j], f[i - 1][j - items[i].w] + items[i].d) # 矩阵
f[j] = max(f[j], f[j - items[i].w] + items[i].d) # 滚动数组
# 若取了第i种物品,则剩下要做的事情就是F(i-1,j- W[i])
# 求从前i-1种物品中选取若干种,在其总体积不超过j一W[i]的条件下所能获得的最大价值
# 第一类取法所能获得的最大价值是F(i-1,j-W[i]) +D[i]
# 若不取第i种物品,则剩下的问题就变成F(i-1,j)
# 第二类取法所能获得的最大价值是F(i-1,j)
print(f[Total_volume]) # f[Total_volume]的值就是F(num_item,Total_volume)
2192:Zipper
# 2192:Zipper
# http://bailian.openjudge.cn/practice/2192/
'''
给定三个字符串,判断是否可以将前两个字符串中的字符组合成第三个字符串。
前两个字符串可以任意混合,但每个字符串必须保持其原始顺序。
'''
def zipperstr1(str1, str2, str3):
dp = [[0 for _ in range(len(str2) + 1)] for _ in range(len(str1) + 1)]
dp[0][0] = 1
for i in range(0, len(str1) + 1): # [0,len(str1)]
for j in range(0, len(str2) + 1): # [0,len(str2)]
# str1的[0,i-1-1]字符 和 str2的[0,j-1]字符 能和 str3的[0,i+j-1-1]字符 匹配 and
# str1的[i-1]字符 能和 str3的[i+j-1]字符 匹配,那么
# str1的[0,i-1]字符 和 str2的[0,j-1]字符 能和 str3的[0,i+j-1]字符 匹配
if (i >= 1 and dp[i - 1][j] == 1 and str1[i - 1] == str3[i + j - 1]):
dp[i][j] = 1
# str1的[0,i-1]字符 和 str2的[0,j-1-1]字符 能和 str3的[0,i+j-1-1]字符 匹配 and
# str2的[j-1]字符 能和 str3的[i+j-1]字符 匹配,那么
# str1的[0,i-1]字符 和 str2的[0,j-1]字符 能和 str3的[0,i+j-1]字符 匹配
if (j >= 1 and dp[i][j - 1] == 1 and str2[j - 1] == str3[i + j - 1]):
dp[i][j] = 1
return dp[len(str1)][len(str2)]
def zipperstr2(str1, str2, str3):
dp = [[0 for _ in range(len(str2) + 1)] for _ in range(len(str1) + 1)]
dp[0][0] = 1
for i in range(0, len(str1) + 1): # [0,len(str1)]
for j in range(0, len(str2) + 1): # [0,len(str2)]
# str1的[0,i-1]字符 和 str2的[0,j-1]字符 能和 str3的[0,i+j-1]字符 匹配 and
# str1的[i]字符 能和 str3的[i+j]字符 匹配,那么
# str1的[0,i]字符 和 str2的[0,j-1]字符 能和 str3的[0,i+j]字符 匹配
if (i < len(str1) and str1[i] == str3[i + j] and dp[i][j]):
dp[i + 1][j] = 1
# str1的[0,i-1]字符 和 str2的[0,j-1]字符 能和 str3的[0,i+j-1]字符 匹配 and
# str2的[j]字符 能和 str3的[i+j]字符 匹配,那么
# str1的[0,i-1]字符 和 str2的[0,j]字符 能和 str3的[0,i+j]字符 匹配
if (j < len(str2) and str2[j] == str3[i + j] and dp[i][j]):
dp[i][j + 1] = 1
return dp[len(str1)][len(str2)]
# 输入的第一行包含一个从 1 到 1000 的正整数。
# 它表示要跟随的数据集的数量。 每个数据集的处理都是相同的。
# 数据集出现在以下几行中,每行一个数据集。
num_dataset = int(input())
i_dataset = 1
while i_dataset <= num_dataset:
# 对于每个数据集,输入行由三个字符串组成,由一个空格分隔。
# 所有字符串仅由大写和小写字母组成。
# 第三个字符串的长度总是前两个字符串的长度之和。
# 前两个字符串的长度将在 1 到 200 个字符之间,包括 1 到 200 个字符。
line = input().split()
str1 = line[0]
str2 = line[1]
str3 = line[2]
if zipperstr1(str1, str2, str3):
print("Data set %d: yes" % (i_dataset))
else:
print("Data set %d: no" % (i_dataset))
i_dataset += 1