- 贪心
- 1、活动安排问题
- 2、区间覆盖问题
- 3、最优装载问题
- 4、多机调度问题
- 一、答疑(贪心)
- 二、巧克力(贪心)
- 三、顺子日期(模拟)
- 四、特殊时间(模拟)
- 五、乘积尾零(模拟)
- 六、平方和(模拟)
- DP
- DP记忆化
- 最经典的DP问题:0/1背包
- 小明的背包1
- 代码1:不带空间优化的
- 代码2:含有空间优化的
- 小明背包2
- 装箱问题(线性DP,0/1背包)
- 2022
- 不用滚动数组,写法一:
- 用滚动数组,写法2:
- 过河卒
贪心
1、活动安排问题
2、区间覆盖问题
3、最优装载问题
4、多机调度问题
一、答疑(贪心)
关键是列出通式!
n=int(input())
q=[]
for i in range(n):
s,a,e=map(int,input().split())
q.append((s,a,e,s+a+e))
q.sort(key =lambda x:x[3])
res=0
for i in range(0,n-1):
res+=(n-i-1)*q[i][3]+q[i][0]+q[i][1]
res+=q[n-1][0]+q[n-1][1]
print(res)
二、巧克力(贪心)
有一个点运行超时了
n, kind = map(int, input().split())
all_list = []
for i in range(kind):
info_list = [int(i) for i in input().split(' ')]
all_list.append(info_list)
all_list.sort(key=lambda x: x[0])
def solve(n, all_list):
c = 0
days = [i for i in range(1, n+1)]
days = sorted(days, reverse=True)
for i in days:
tmp_c = 0
for j in all_list:
if j[2] > 0:
if j[1] >= i:
tmp_c += j[0]
index = all_list.index(j)
all_list[index][2] -= 1
break
if tmp_c == 0:
return -1
else:
c += tmp_c
return c
print(solve(n, all_list))
三、顺子日期(模拟)
mon=[0,31,28,31,30,31,30,31,31,30,31,30,31]
def check(s):
if "012" in s:
return True
if "123"in s:
return True
return False
res=0
s="2022"
for i in range(1,12+1):
for j in range(1,mon[i]+1):
if i<10:
ss=s+"0"+str(i)
else:
ss=s+str(i)
if j<10:
ss=ss+"0"+str(j)
else:
ss=ss+str(j)
if check(ss):
# print(ss)
res+=1
print(res)
四、特殊时间(模拟)
day_per_month = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
#检查日期D是否合法
def check_D(D):
month = D // 100
day = D % 100
if month < 1 or month > 12:
return 0
if day < 1 or day > day_per_month[month]:
return 0
return 1
#检查时刻H是否合法
def check_H(H):
h = H // 100
m = H % 100
if h < 0 or h > 23:
return 0
if m < 0 or m > 59:
return 0
return 1
ans = 0
#枚举第一个数字
for a in range(10):
#枚举第二个数字
for b in range(10):
if a == b:
continue
#合法数量
N_Y, N_D, N_H = 4, 0, 0
A = [a, a, a, a]
#枚举四种情况aaab、aaba、abaa、baaa
for i in range(4):
A[i] = b
number = 0
for j in A:
number = number * 10 + j
N_D += check_D(number)
N_H += check_H(number)
A[i] = a
ans += N_Y * N_D * N_H
print(ans)
五、乘积尾零(模拟)
a=[5650,4542,3554,473,946,4114,3871,9073,90,4329,2758,7949,6113,5659,5245,7432,3051,4434,6704,3594,9937,
1173,6866,3397,4759,7557,3070,2287,1453,9899,1486,5722,3135,1170,4014,5510,5120,729,2880,9019,
2049,698,4582,4346,4427,646,9742,7340,1230,7683,5693,7015,6887,7381,4172,4341,2909,2027,7355,5649,
6701,6645,1671,5978,2704,9926,295,3125,3878,6785,2066,4247,4800,1578,6652,4616,1113,6205,3264,2915,
3966,5291,2904,1285,2193,1428,2265,8730,9436,7074,689,5510,8243,6114,337,4096,8199,7313,3685,211 ]
res=1
for i in a:
res*=i
ans=0
while res%10==0:
ans+=1
res//=10
print(ans)
六、平方和(模拟)
def check(u):
u=str(u)
if "2" in u or "0" in u or "1" in u or "9" in u:
return True
return False
res=0
for i in range(1,2019+1):
if check(i):
res+=i*i
print(res)
DP
DP记忆化
动态规划又叫暴力的剪枝
最经典的DP问题:0/1背包
小明的背包1
代码1:不带空间优化的
def solve(n,C):
for i in range(1,n+1):
for j in range(0,C+1):
if c[i]>j:#装不下的情况
dp[i][j]=dp[i-1][j]
else:
dp[i][j]=max(dp[i-1][j],dp[i-1][j-c[i]]+w[i])
return dp[n][C]
N=3011
dp=[[0 for i in range(N)]for j in range(N)]
w=[0]*N
c=[0]*N
n,C=map(int,input().split())
for i in range(1,n+1):
c[i],w[i]=map(int,input().split())
print(solve(n,C))
代码2:含有空间优化的
def solve(n,C):
now = 0
old = 1
for i in range(1,n+1):
old,now = now,old #交换
for j in range (0,C+1):
if c[i] > j: dp[now][j] = dp[old][j]
else: dp[now][j] = max(dp[old][j], dp[old][j-c[i]]+w[i])
return dp[now][C]
N = 3011
dp = [[0 for i in range(N)] for j in range(2)] #注意先后
w = [0]*N
c = [0]*N
n, C = map(int, input().split())
for i in range(1, n+1): c[i], w[i] = map(int, input().split())
print(solve(n, C))
小明背包2
N, V = map(int, input().split())
dp = [0]*(V+1)
for _ in range(N):
w, v = map(int, input().split())
for j in range(w, V+1):
dp[j] = max(dp[j], dp[j-w]+v)
print(dp[-1])
装箱问题(线性DP,0/1背包)
V=int(input())
n=int(input())
dp = [0]*(V+1)
for i in range(n):
v = int(input())
for j in reversed(range(v, V+1)):
dp[j] = max(dp[j], dp[j-v]+v)
print(V-dp[V])
2022
有两种方法,可以用暴力来做,反正是填空题,就是算C2022^10
不用滚动数组,写法一:
dp=[[[0 for _ in range(2222)]for j in range(11)]for i in range(2222)]
#初始化
for i in range(2023):
dp[i][0][0]=1
for i in range(1,2023):
for j in range(1,11):
for k in range(1,2023):
if k<i:
dp[i][j][k]=dp[i-1][j][k]
else:#从1~i个数里选择前j个数,他们的和为k
dp[i][j][k]=dp[i-1][j][k]+dp[i-1][j-1][k-i]
print(dp[2022][10][2022])
用滚动数组,写法2:
dp=[[0 for _ in range(2222)]for i in range(11)]
#初始化
dp[0][0]=1
for i in range(1,2023):
for j in range(10,0,-1):
for k in range(i,2023):
dp[j][k]+=dp[j-1][k-i]
print(dp[10][2022])
过河卒
dp=[[0 for i in range(25)]for j in range(25)]
n,m,p,q=map(int,input().split())
n+=2
m+=2
p+=2
q+=2
s=[[0 for i in range(25)]for j in range(25)]
s[p][q]=1
s[p-2][q-1],s[p-1][q-2],s[p+1][q-2],s[p+2][q-1],s[p+2][q+1],s[p+1][q+2],s[p-1][q+2],s[p-2][q+1]=1,1,1,1,1,1,1,1
dp[2][1]=1
for i in range(2,n+1):
for j in range(2,m+1):
if s[i][j]==1:
dp[i][j]=0
else:
dp[i][j]=dp[i-1][j]+dp[i][j-1]
print(dp[n][m])