不知不觉已经准备这么久了,希望明天好运
目录
数位dp之k好数
盲猜会考数位dp,紧急复习一下
def dfs():
global n
num=[]
while n!=0:
num.append(n%k)
n//=k
ans=0
last=-5
for i in range(len(num)-1,-1,-1):
x=num[i]
for q in range(x):
if abs(last-q)!=1:
ans+=dp[i+1][q]
if abs(last-x)==1:
break
print(ans)
k,l=map(int,input().split())
dp=[[0 for i in range(k)]for j in range(l+1)]
for i in range(k):
for j in range(k):
if abs(i-j)!=1:
dp[2][i]+=1
for i in range(3,l+1):
for j in range(k):
for z in range(k):
if abs(j-z)!=1:
dp[i][j]+=dp[i-1][z]
n=0
for i in range(l):
n+=(k-1)*pow(k,i)
dfs()
图论
dijkstra
def dijkstra():
d=[1<<31 for i in range(n+1)]
d[1]=0
vis=[False for i in range(n+1)]
for i in range(n):
index=-1
minlength=1<<31
for j in range(1,n+1):
if not vis[j] and d[j]<minlength:
index=j
minlength=d[j]
if index==-1:
return -1
vis[index]=True
for j in adj[index]:
ne,va=j
if not vis[ne] and d[ne]>d[index]+va:
d[ne]=d[index]+va
print(d[n])
n,m=map(int,input().split())
adj=[[]for i in range(n+1)]
for i in range(m):
x,y,z=map(int,input().split())
adj[x].append((y,z))
dijkstra()
Bellman_Ford
要注意备份距离数组
判断不可到达时使用1<<30,应该可能被稍微更新一点
import copy
def bellman_ford():
d=[1<<31 for i in range(n+1)]
d[1]=0
for i in range(k):
dc=copy.deepcopy(d)
for j in range(1,n+1):
for z in adj[j]:
ne,va=z
if d[ne]>dc[j]+va:
d[ne]=dc[j]+va
print(d[n])
n,m,k=map(int,input().split())
adj=[[]for i in range(n+1)]
for i in range(m):
x,y,z=map(int,input().split())
adj[x].append((y,z))
bellman_ford()
SPFA
求最短路
def spfa():
from collections import deque
q=deque([])
d=[1<<31 for i in range(n+1)]
d[1]=0
q.append(1)
while q:
top=q.popleft()
for i in adj[top]:
ne,va=i
if d[ne]>d[top]+va:
d[ne]=d[top]+va
if ne not in q:
q.append(ne)
print(d[n])
n,m=map(int,input().split())
adj=[[]for i in range(n+1)]
for i in range(m):
x,y,z=map(int,input().split())
adj[x].append((y,z))
spfa()
判断负环
def spfa():
flag=False
from collections import deque
q=deque([])
d=[1<<31 for i in range(n+1)]
d[1]=0
q.append(1)
num=[0 for i in range(n+1)]
while q:
top=q.popleft()
for i in adj[top]:
ne,va=i
if d[ne]>d[top]+va:
d[ne]=d[top]+va
num[ne]+=1
if num[ne]>n:
flag=True
break
if ne not in q:
q.append(ne)
if flag:
break
if flag:
print("YES")
n,m=map(int,input().split())
adj=[[]for i in range(n+1)]
for i in range(m):
x,y,z=map(int,input().split())
adj[x].append((y,z))
spfa()
floyd求最短路
def floyd():
#初始化
for i in range(1,n+1):
adj[i][i]=0
for k in range(1,n+1):
for i in range(1,n+1):
for j in range(1,n+1):
adj[i][j]=min(adj[i][j],adj[i][k]+adj[k][j])
return
n,m,k=map(int,input().split())
adj=[[1<<31 for i in range(n+1)]for j in range(n+1)]
for i in range(m):
x,y,z=map(int,input().split())
adj[x][y]=z
floyd()
for i in range(k):
x,y=map(int,input().split())
if adj[x][y]>=1<<30:
print("impossible")
else:
print(adj[x][y])
prim算法
def prim():
d=[1<<31 for i in range(n+1)]
d[1]=0
vis = [False for i in range(n + 1)]
ans=0
for i in range(1,n+1):
minlength=1<<31
index=-1
if not vis[i] and d[i]<minlength:
minlength=d[i]
index=i
if index==-1:
return False
ans+=minlength
vis[index]=True
for j in adj[index]:
ne,va=j
if d[ne]>va:
d[ne]=va
print(ans)
n,m=map(int,input().split())
adj=[[]for i in range(n+1)]
for i in range(m):
x,y,z=map(int,input().split())
adj[x].append((y,z))
adj[y].append((x,z))
prim()
kruskal算法
def find(x):
if x!=fa[x]:
fa[x]=find(fa[x])
return fa[x]
n,m=map(int,input().split())
fa=[i for i in range(n+1)]
ans=0
for i in range(m):
x,y,z=map(int,input().split())
fax=find(x)
fay=find(y)
if fax!=fay:
fa[fax]=fay
ans+=z
print(ans)
染色法判断二分图
注意这个图可能不是联通的
def dfs(cur,fa,c):
color[cur]=c
for ne in adj[cur]:
if ne!=fa:
if color[ne]==0:
if not dfs(ne,cur,3-c):
return False
else:
if color[ne]==color[cur]:
return False
return True
n,m=map(int,input().split())
adj=[[]for i in range(n+1)]
for i in range(m):
x,y=map(int,input().split())
adj[x].append(y)
adj[y].append(x)
flag=True
color=[0 for i in range(n+1)]
for i in range(1,n+1):
if color[i]==0:
if not dfs(i,-1,1):
flag=False
break
if flag:
print("Yes")
else:
print("No")
匈牙利算法
def dfs(cur):
for i in a[cur]:
if not st[i]:
st[i]=True
if right[i]==0 or dfs(right[i]):
right[i]=cur#别漏了这个
return True
else:
return False
return False
n1,n2,k=map(int,input().split())
a=[[]for i in range(n1+1)]
b=[[]for i in range(n2+1)]
for i in range(k):
x,y=map(int,input().split())
a[x].append(y)
right=[0 for i in range(n2+1)]
ans=0
for i in range(1,n1+1):
st=[False for i in range(n1+1)]
if dfs(i):
ans+=1
print(ans)
搜索
DFS
排列数
def dfs(cur,path):
if len(path)==3:
for i in path:
print(i,end=" ")
print()
return
for i in range(1,n+1):
if not vis[i]:
vis[i]=True
dfs(i,path+[i])
vis[i]=False
return
n=int(input())
vis=[False for i in range(n+1)]
dfs(0,[])
n皇后问题
def isvalid(path,x):
n=len(path)
flag=True
for i in range(n):
if abs(n-i)==abs(x-path[i]):
flag=False
break
return flag
def dfs(cur,a):
if cur==n:
print(a)
return
for i in range(n):
if not a or (i not in a and isvalid(a,i)) :
dfs(cur+1,a+[i])
return
n=int(input())
dfs(0,[])
树的重心
BFS
走迷宫
def isvalid(x,y):
if x<0 or x>=n:
return False
if y<0 or y>=m:
return False
if adj[x][y]==1:
return False
return True
dx=[1,-1,0,0]
dy=[0,0,1,-1]
def bfs():
from collections import deque
q=deque([])
q.append(start)
vis=[[False for i in range(m)]for j in range(n)]
vis[0][0]=True
ans=0
while q:
size=len(q)
for i in range(size):
top=q.popleft()
if top==end:
print(ans)
return
for i in range(4):
nx,ny=top[0]+dx[i],top[1]+dy[i]
if isvalid(nx,ny) and not vis[nx][ny]:
q.append((nx,ny))
vis[nx][ny]=True
ans+=1
八数码
def isvalid(x,y):
if x<0 or x>=3:
return False
if y<0 or y>=3:
return False
return True
dx=[1,-1,0,0]
dy=[0,0,1,-1]
def bfs():
from collections import deque
q=deque([])
q.append(a)
vis=dict()
vis[a]=True
ans=0
while q:
size=len(q)
for i in range(size):
top=q.popleft()
if top==end:
print(ans)
return
index=top.index('x')
x=index//3
y=index%3
for j in range(4):
nx,ny=x+dx[j],y+dy[j]
if isvalid(nx,ny):
nindex=nx*3+ny
s=list(top)
s[index],s[nindex]=s[nindex],s[index]
s="".join(s)
if s not in vis:
vis[s]=True
q.append(s)
ans+=1
return
a="".join(input().split())
end="12345678x"
bfs()
数论
素数
def getprime():
for i in range(2,N):
if not vis[i]:
vis[i]=True
prime.append(i)
pre[i]=i
for j in prime:
x=i*j
if x>=N:
break
vis[x]=True
pre[x]=j
if i%j==0:
break
N=100
prime=[]
vis=[False for i in range(N)]
pre=[-1 for i in range(N)]
getprime()
print(prime)
扩展欧几里得算法
def egcd(a,b):
if b==0:
return 1,0,a
else:
x,y,d=egcd(b,a%b)
x,y=y,x-(a//b)*y
return x,y,d
a,b=map(int,input().split())
x,y,d=egcd(a,b)
q=100
y*=q//d#放大一定倍数
a//=d#后面取余
y=y%a
更相损减法
def egcd(x,y):
if x<y:
x,y=y,x
if y==1:
return x
else:
return egcd(y,x//y)
x,y=map(int,input().split())
print(egcd(x,y))
动态规划
01背包问题
n,m=map(int,input().split())
v,w=[0],[0]
for i in range(n):
vi,wi=map(int,input().split())
v.append(vi)
w.append(wi)
dp=[[0 for i in range(m+1)]for j in range(n+1)]
for i in range(1,n+1):
for j in range(m+1):
dp[i][j]=dp[i-1][j]
if j>=v[i]:
dp[i][j]=max(dp[i][j],w[i]+dp[i-1][j-v[i]])
print(dp[n][m])
完全背包问题
n,m=map(int,input().split())
v,w=[0],[0]
for i in range(n):
vi,wi=map(int,input().split())
v.append(vi)
w.append(wi)
dp=[[0 for i in range(m+1)]for j in range(n+1)]
for i in range(1,n+1):
for j in range(m+1):
dp[i][j]=dp[i-1][j]
if j>=v[i]:
dp[i][j]=max(dp[i][j],w[i]+dp[i][j-v[i]])
print(dp[n][m])
多重背包
n,m=map(int,input().split())
v=[0]
w=[0]
for i in range(n):
vi,wi,ki=map(int,input().split())
num=1
while ki>=num:
v.append(vi*num)
w.append(wi*num)
ki-=num
num*=2
if ki!=0:
v.append(vi*ki)
w.append(wi*ki)
n=len(v)-1
dp=[[0 for i in range(m+1)]for j in range(n+1)]
for i in range(1,n+1):
for j in range(m+1):
dp[i][j]=dp[i-1][j]
if j>=v[i]:
dp[i][j]=max(dp[i][j],w[i]+dp[i-1][j-v[i]])
print(dp[n][m])
分组背包问题
n,m=map(int,input().split())
a=[[]for i in range(n+1)]
for i in range(1,n+1):
x=int(input())
for j in range(x):
x,y=map(int,input().split())
a[i].append((x,y))
dp=[[0 for i in range(m+1)]for j in range(n+1)]
for i in range(1,n+1):
for j in range(m+1):
dp[i][j]=dp[i-1][j]
for k in a[i]:
v,w=k
if j>=v:
dp[i][j]=max(dp[i][j],dp[i-1][j-v]+w)
print(dp[n][m])
数字三角形
n=int(input())
adj=[[-1<<31 for i in range(n+2)]for j in range(n+1)]
for i in range(1,n+1):
a=list(map(int,input().split()))
for j in range(len(a)):
adj[i][j+1]=a[j]
for i in range(2,n+1):
for j in range(1,i+1):
adj[i][j]+=max(adj[i-1][j],adj[i-1][j-1])
print(max(adj[-1]))
最长上升子序列
n=int(input())
a=list(map(int,input().split()))
dp=[1 for i in range(n)]
for i in range(1,n):
for j in range(i):
if a[i]>a[j]:
dp[i]=max(dp[i],dp[j]+1)
print(max(dp))
最长公共子序列
n,m=map(int,input().split())
a=" "+input()
b=" "+input()
dp=[[0 for i in range(m+1)]for j in range(n+1)]
for i in range(1,n+1):
for j in range(1,m+1):
if a[i]==b[j]:
dp[i][j]=max(dp[i][j],dp[i-1][j-1]+1)
dp[i][j]=max(dp[i][j],dp[i-1][j],dp[i][j-1])
print(dp[n][m])
最短编辑距离
n=int(input())
a=" "+input()
m=int(input())
b=" "+input()
dp=[[0 for i in range(m+1)]for j in range(n+1)]
for i in range(1,n+1):
for j in range(1,m+1):
dp[i][j]=max(dp[i-1][j],dp[i][j-1])
if a[i]==b[j]:
dp[i][j]=max(dp[i][j],dp[i-1][j-1]+1)
num=dp[n][m]
print(max(n,m)-num)
石子合并
n=int(input())
a=[0]+list(map(int,input().split()))
for i in range(1,n+1):
a[i]+=a[i-1]
dp=[[1<<31 for i in range(n+1)]for j in range(n+1)]
for i in range(1,n+1):
dp[i][i]=0
for k in range(1,n):
for i in range(1,n):
l=i
r=i+k
if r>n:
break
for j in range(l,r):
dp[l][r]=min(dp[l][r],dp[l][j]+dp[j+1][r]+a[r]-a[l-1])
print(dp[1][n])
整数划分
n=int(input())
dp=[[0 for i in range(n+1)]for j in range(n+1)]
dp[0][0]=1
for i in range(1,n+1):
for j in range(n+1):
dp[i][j]+=dp[i-1][j]
if j>=i:
dp[i][j]+=dp[i][j-i]
print(dp[n][n])
蒙德里安的梦想
while True:
n,m=map(int,input().split())
st=[True for i in range(1<<n)]
for i in range(1<<n):
cnt=0
flag=True
for k in range(n):
if i>>k&1==0:
cnt+=1
else:
if cnt%2==1:
flag=False
break
cnt=0
if cnt%2==1:
flag=False
if not flag:
st[i]=False
dp=[[0 for i in range(1<<n)]for j in range(m+1)]
dp[0][0]=1
for i in range(1,m+1):
for j in range(1<<n):
for k in range(1<<n):
if j&k==0 and st[j|k]:
dp[i][j]+=dp[i-1][k]
print(dp[m][0])
最短哈密尔顿路径
n=int(input())
adj=[]
for i in range(n):
adj.append(list(map(int,input().split())))
dp=[[1<<31 for i in range(1<<n)]for j in range(n)]
dp[0][1]=0
for j in range(1<<n):
for i in range(n):
if j>>i&1:
for k in range(n):
if (j-(1<<i))>>k&1:
dp[i][j]=min(dp[i][j],adj[k][i]+dp[k][j-(1<<i)])
print(dp[n-1][(1<<n)-1])
没有上司的舞会
def dfs(cur):
ci,nci=a[cur],0
for i in adj[cur]:
x=dfs(i)
ci+=x[1]
nci+=max(x)
return (ci,nci)
n=int(input())
a=[0]
for i in range(n):
a.append(int(input()))
adj=[[]for i in range(n+1)]
st=[False for i in range(n+1)]
for i in range(n-1):
l,k=map(int,input().split())
st[l]=True
adj[k].append(l)
fa=-1
for i in range(1,n+1):
if not st[i]:
fa=i
ans=dfs(fa)
print(max(ans))
滑雪
dx=[1,-1,0,0]
dy=[0,0,1,-1]
def isvalid(x,y):
if x<0 or x>=n:
return False
if y<0 or y>=m:
return False
return True
def dfs(x,y):
if dp[x][y]!=-1:
return dp[x][y]
cur=1
for i in range(4):
nx,ny=x+dx[i],y+dy[i]
if isvalid(nx,ny) and adj[nx][ny]<adj[x][y]:
cur=max(cur,dfs(nx,ny)+1)
dp[x][y]=cur
return cur
n,m=map(int,input().split())
adj=[]
for i in range(n):
adj.append(list(map(int,input().split())))
ans=0
dp=[[-1 for i in range(m)]for j in range(n)]
for i in range(n):
for j in range(m):
if dp[i][j]==-1:
ans=max(ans,dfs(i,j))
print(ans)