Floyd算法又被称为插点法,是利用动态规划的思想在给定的加权图中寻找多源点之间最短路径的方法。
在此算法中每个点都是潜在的中转站,也就是每个点都可能对另外两个点之间的最短路径造成影响。
通常在处理问题的时候采用一维数组来储存每个单独的点的位置数据,同时生成邻接数组来记录每个点初始距离数据,之后每个领接数组的点都会进行n次试探(此时的n为问题当中给出的数据个数)用来判断两个点之间最小距离是原始值还是有某个点可以作为中转站使得距离比原始值更小。
这里用一道题来说明「一本通 1.2 练习 2」扩散
题中要求找到某个时间使所有的点经过扩散后恰好连通起来。可以发现给出两个点之间的距离是两个点的横坐标的差值与横坐标差值的和除以二,若和为奇数还需要加一。此时我们就可以明显的发现此题可以采用Floyd算法加上动态规划的思想解决。
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n,a[55],b[55];
cin>>n;
for(int c=0;c<n;c++) cin>>a[c]>>b[c];
int i[55][55];
for(int c=0;c<n;c++){
for(int d=0;d<c;d++){
i[c][d]=i[d][c]=abs(a[c]-a[d])+abs(b[c]-b[d]);//“1”
}
}
for(int k=0;k<n;k++){
for(int c=0;c<n;c++){
for(int d=0;d<n;d++){
i[c][d]=min(i[c][d],max(i[c][k],i[k][d]));//“2”
}
}
}
int ans=0;
for(int c=0;c<n;c++){
for(int d=0;d<c;d++){
ans=max(ans,i[c][d]);
}
}
cout<<(ans+1)/2;//“3”
}
这里对代码处做出两点解释
备注的第一处领接数组的初处理,表示c点位置与d点位置的初始距离,自然c点到d点的距离是等于d点到c点的距离的。
第二处是代码中体现floyd思想的地方,这里采用了三个循环来对邻接数组再次进行处理。内部两个循环是用来遍历一遍邻接数组,最外面的循环用来遍历一遍点的个数用来插入到两个点之间用来试探,这一步是通过代码 max(i[c][k],i[k][d]) 来实现的 这里表示在c到k和k到d之间找到一个较大值(当距离大的一组点相遇时另一组也必然相遇了)再与原始值比较用来选出较小值。
(ans+1)/2 : 完美的达到了ans为奇数加1而偶数而不做处理的目的。当ans为奇数时两点相距地距离需要再加1,而为偶数时因为ans为int类型加上1后除以2依然只保留整数部分所以再加上1对答案不影响。
总结一下floyd算法:
floyd算法是经典的动态规划问题,将需要解决的一个大的问题分解为数个小的问题依次解决。将多源路径拆分为数个分组,再从每个分组单独多次讨论是否含有中间值对最小多源路径有影响。
我是笨蛋