邮递员送信
链接:www.luogu.com.cn/problem/P16…
Dijkstra:
Dijkstra的重点在于把每个点到某一个点的最短距离纪录下来,更新距离的过程就可以用一个字典来存边,比如出发的点为字典的keys,之后依次遍历就好了,而每次都用最短距离的点进行更新,但是这个题目还需要返回,就需要加入图论中的翻转操作.假设要问从x到1的最短路,为x->a->b->c->1,也就是说x->a,a->b,b->c,c->1都有路可走,那么我们想想,从x开始x->a,a->b,b->c,c->1的最短路不就是从1开始1->c,c->b,b->a,a->x的最短路吗?于是这时,我们把x->a,a->b,b->c,c->1这4条路径变为1->c,c->b,b->a,a->x,然后从1开始跑最短路,而它们的最短路是一样的。
code
#Dijkstra算法
from collections import defaultdict
sumvalue=0
def Dijkstra(road_dict):
global sumvalue
dist = [float('inf') for node in range(n + 1)] # 存储最小路径
seen = [0 for i in range(n + 1)] # 标记数组初始化
dist[1] = 0 # 自身已经求出最短距离,进行计算
while True:
next_node = 0 # 首先初始化的时候就代表不能找到最小的
for i in range(1, n + 1): # 遍历n个点,然后依次用
if not seen[i] and dist[i] < dist[next_node]: # 找到这个里面最小的
next_node = i # 最短的目的地就是i说明
if next_node == 0: #如果没有找到就说明都已经遍历完或者没有更多的节点
break
seen[next_node] = 1
for k, l in road_dict[next_node]: # 使用字典的原因就是可以直接找到相应的节点边
dist[k] = min(dist[k], dist[next_node] + l) # 也
for i in range(2, n + 1): # 需要计算出
sumvalue += dist[i] #
n,m = map(int,input().split()) #n为节点个数,m为边个数
road_dict =defaultdict(list) #默认为list的字典
road_reverse_dict=defaultdict(list) #反向建立边
for i in range(m):
u,v,w = map(int,input().split()) #使用了u,v,w
road_dict[u].append((v,w)) #去的路上路径
road_reverse_dict[v].append((u,w)) #反向建立边
Dijkstra(road_dict)
Dijkstra(road_reverse_dict)
print(sumvalue)
Job Hunt S
因为这个里面需要求最长路,于是将其处理成求负权的最小值,使用spfa算法(链接:
搭配购买
这道题其实就是并查集与01背包的组合题,首先使用并查集将所有的物品价值和价格加起来.然后看成一种物品进行背包问题求解即可.
import collections
father_dict = {}
size_dict = {}
def init(n):
global father_dict
for i in range(1,n+1):
father_dict[i] = i
size_dict[i]=1 #优先度为1
def union(x,y): #将两个集合并起来
global father_dict,size_dict
x = find(x)
y = find(y)
if(x!=y): #两个集合不是一样的话
size_dict_x = size_dict[x]
size_dict_y = size_dict[y]
if(size_dict_x>=size_dict_y):
father_dict[y] = x
size_dict[x] += size_dict_y
else:
father_dict[x] = y
size_dict[y] += size_dict_x
def find(x):
global father_dict
root = x
while(root!=father_dict[root]):
root = father_dict[root] #一直寻找其父节点
while(x != root): #一直更新
t = father_dict[x] #更新所在的集合
father_dict[x] = root
x = t
return root
n,m,w =map(int,input().split()) #也就是使用三个数字
init(n)
weights =[0 for i in range(n+1)]
price = [0 for i in range(n+1)]
for i in range(1,n+1):
c,d =map(int,input().split())
weights[i] = d
price[i] = c
for j in range(m):
u,v = map(int,input().split())
union(u,v) #联合u,v
for i in range(1,n+1): #
if(father_dict[i]!=i): #如果相等的话就没必要比较了
weights[father_dict[i]] += weights[i]
weights[i] = 0
price[father_dict[i]] += price[i]
price[i] = 0
#为何不能列表相加
#接下来进行dp
dp = [0 for i in range(w+1)] #有很多钱
for i in range(1,n+1):
for j in range(w,price[i]-1,-1): #w为最大值,从最大值遍历到最小值
dp[j] = max(dp[j-price[i]]+weights[i],dp[j]) #也就是如果用这个更大了的话
print(dp[w])
\