本文章为原创文章,未经过允许不得转载
运行要求
运行时间限制: 2sec
内存限制: 1024MB
未经允许,不得许转载
原题链接
题目
魔法少女想要把这个世界上所有的数字都变为1
把一个数字从i变成j需要cij个魔法点数。0<=i,j<=9
现在面前有一堵墙,宽为W,高为H。只要有一个砖块里写着0以上9以下的整数。
从上往下,从左往右i行(1<=i<=H),第j列(1<=j<=W),写着数情报Aij
- Aij = -1 的情况下,代表砖头上没有写数字
- Aij != -1 的情况下,代表砖头上写着数字Aij
求把墙壁上所有的数字都变成1,所需要的最小魔法值。
输入前提条件
- 所有的输入均为整数
- 1 <= H,W <= 200
- cij = 0 (i = j)
- -1 <= Aij <= 9
- 墙上至少写了一个整数
输入
输入按照以下形式标准输入
H W
c0,0 ... c0,9
::
c9,0 ... c9,9
A1,1 ... A1,W
:
AH,1 ... AH,W
输出
输出把墙壁上所有的数都变成1,所需要的最小魔法值
例1
输入
2 4
0 9 9 9 9 9 9 9 9 9
9 0 9 9 9 9 9 9 9 9
9 9 0 9 9 9 9 9 9 9
9 9 9 0 9 9 9 9 9 9
9 9 9 9 0 9 9 9 9 2
9 9 9 9 9 0 9 9 9 9
9 9 9 9 9 9 0 9 9 9
9 9 9 9 9 9 9 0 9 9
9 9 9 9 2 9 9 9 0 9
9 2 9 9 9 9 9 9 9 0
-1 -1 -1 -1
8 1 1 8
输出
12
要把8变成1的话,先把8变成4,再把4变成9
墙壁上有2个8,所以总共需要6*2=12点魔法值
例2
输入
5 5
0 999 999 999 999 999 999 999 999 999
999 0 999 999 999 999 999 999 999 999
999 999 0 999 999 999 999 999 999 999
999 999 999 0 999 999 999 999 999 999
999 999 999 999 0 999 999 999 999 999
999 999 999 999 999 0 999 999 999 999
999 999 999 999 999 999 0 999 999 999
999 999 999 999 999 999 999 0 999 999
999 999 999 999 999 999 999 999 0 999
999 999 999 999 999 999 999 999 999 0
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1
输出
0
请注意,墙壁上的数不需要改变的情况
例3
输入
3 5
0 4 3 6 2 7 2 5 3 3
4 0 5 3 7 5 3 7 2 7
5 7 0 7 2 9 3 2 9 1
3 6 2 0 2 4 6 4 2 3
3 5 7 4 0 6 9 7 6 7
9 8 5 2 2 0 4 7 6 5
5 4 6 3 2 3 0 5 4 3
3 6 2 3 4 2 4 0 8 9
4 6 5 4 3 5 3 2 0 8
2 1 3 4 5 7 8 6 4 0
3 5 2 6 1
2 5 3 2 1
6 9 2 5 6
输出
47
读懂题目
墙上写的cij的情报,代表了两个点之间的相互距离
如图所示,打个比方。有4个点。左边是墙上的情报。墙上的情报代表点和点之间的相互距离。右边的图,描绘了点和点之间的距离。
解题思路
我们已知点和点之间的直接距离。每个点到1的距离的和就是把所有的点变成1所需要的魔法值
但是,每个点到1的路线,除了直接线路以外,还有间接线路
比如上图中,1到4的直接距离是180
但是1到4的间接路线还有1->2->4
总共消耗65点魔法值
因此可以看出,每个点到1的路线虽然有直接路线,但是因为其他路线也通。所以,对于每一个点,我们要找到这个点到1的最短路径。
直接了断来说,floyd算法求最短路径
步骤
- 遍历每一个点,把这个点看作中转站A。
- 在1的基础上遍历所有的点。所有的点,包括这个点自己,比如点X,经过这个中转站A,到达目标点B的距离设为distanceXAB
- 点X到目标点B的目前最短距离为XB(注意,这里可能已经不是直接距离了)
- 对比,distanceXAB和distanceXB,如果distanceXAB比distanceXB要小,那么用distanceXB去覆盖distanceXAB。覆盖的不光是距离,还有路线
以1为中转站
如上图,刚开始的时候,1为中转站,我们发现经过1到达别的地方,和直接到达别的地方相比,要么距离一样,要么还要远
3->1->4 distance = 20+180 = 200
3->4 distance = 5
1->1 distance = 0
1->1->1 distance = 0
我们不更新路径
以2为中转站
这种情况下
1->4 distance = 180
1->2->4 distance = 65
1经过2到4
比
目前的1直接到4
的路径距离要近
我们用1->2->4的路线去覆盖1->4的路线
用65去覆盖180
类似的情况还有1到3,3到1,4到1
以3为中转站
同理,当遍历到3,以3为中转站的时候
比如1-4的走法,已经被更新为1->2->4 distnace 65
但是如果经过3的话,1->2->3->4 distance 16
显然经过3到4会更近
1到4,2到4
4到1,4到2
会在原来的基础上选择经过3来到达目的地,这样会更近一些
以4为中转站
我们发现在已有的路线下,好多都已经不是原本的直达,就算经过4也没能缩短路径距离,所以没有线路被更新
就这样遍历每个点,把每个点当作中转站,然后判断是不是要经过这个中转站
总结
floyd算法求最短路径的精髓就在于,每次短路线覆盖长路线,覆盖的不仅仅是距离本身,实际上还隐藏覆盖了路线
代码
H, W = map(int,input().split())
ARR = []
for i in range(10):
res = list(map(int, input().split()))
ARR.append(res)
CRR = []
for i in range(H):
CRR.append(list(map(int, input().split())))
def calculate(h, w, arr, crr):
for i in range(0, 10):
for j in range(0, 10):
for k in range(0, 10):
s1 = arr[j][i] + arr[i][k]
s2 = arr[j][k]
arr[j][k] = min(s1, s2)
result = 0
for cr in crr:
for c in cr:
if c == -1:
continue
else:
result += arr[c][1]
print(result)
calculate(H, W, ARR, CRR)
总结
※ 另外,我会在我的微信个人订阅号上推出一些文章,欢迎关注
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。