弗洛伊德算法其实是一种非常简单的图论算法,总的来说,弗洛伊德算法甚至可以说是一种暴力枚举。
弗洛伊德算法是解决任意两点间的最短路径的一种算法,可以正确处理有向图或负权(但不可存在负权回路)的最短路径问题,同时也被用于计算有向图的传递闭包。——弗洛伊德算法的定义。
从出发地到目的地的过程中,我们并不是一下子就到达目的地,而是要经过很多的中转站来帮助我们一步一步地到达目的地。例如下面的图中,假设 AB,BC 之间的距离分别为 7 和 2。我们看到,A 和 C 之间不能直接通达,因此,要计算 A 和 C 之间的距离,我们就要借助 B 来作为中转站,因此 A 到 C 的距离为 7 + 2 = 9。
但是,单凭一个中转站在有些情况下也是不行的,比如从 D 到 F 就不能只通过一个中转站。
因此,计算所有节点之间的最短距离这个大问题可以分为借助2个中转站的情况下计算各节点之间的最短路径
下面来谈一下具体的求解过程,我们首先用邻接矩阵来表示这张图,其中 表示两个节点之间不能相互直达,矩阵中每一项的数字代表边的权重,也就是节点之间的距离。
上面的矩阵也可以代表在不借助中转站的情况下各节点之间的最短路径。接下来,我们只让节点 A 作为中转站,然后计算各节点的最短路径,然后对于矩阵的每一项,我们比较d[i][j]
和d[i][1]+d[1][j]
的大小,然后取最小者作为d[i][j]
的值。其中i
和j
分别代表矩阵的行和列。
计算后我们发现矩阵中的第 2 行第 5 列变为了 ,说明从节点 B 到节点 E 的最短距离在当前状态下为 。接下来,我们逐渐增加中转站的个数,每增加一个中转站的个数,矩阵就更新一次。假设中转站的个数为 ,那么它与上一个状态 之间存在这样的关系d[i][j] = min(d[i][j], d[i][k] + d[k][j])
,于是 从 递增到 ,每递增一次,矩阵的值就更新一次,最后我们就得到所有点对的最短距离了。
接下来我们就看一道题来帮助我们理解:
你也被霍格沃茨学校选中学习魔法课,但你碰到了一点小麻烦,因为他并不像哈利波特那样能够记住所有的咒语而随意的将一个足球变成猴子,但是你发现了变形咒语的一个统一规律:如果咒语是以a开头b结尾的一个单词,那么它的作用就恰好是使A物体变成B物体。你将所会的所有咒语都列成了一个表,现在你计算一下自己是否能完成老师的作业,将一个B(ball)变成一个M(Mouse),你知道,如果自己不能完成的话,就只好向哈利波特请教,并且被迫听一大堆好好学习的道理。
Input
测试数据有多组。每组有多行,每行一个单词,仅包括小写字母,是你所会的所有咒语.数字0表示一组输入结束.
Output
如果你可以完成自己的作业,就输出"Yes",否则就输出"No"
Sample Input
so
soon
river
goes
them
got
moon
begin
big
0
Sample Output
Yes.
//可以念这个咒语:“big-got-them”.
这道题当然可以用其他算法解决,但我首先想到的还是弗洛伊德,因为我其他算法学的并不怎么样
#include<bits/stdc++.h> // 万能头
using namespace std;
string s[10001];
int n;
int a[27][27];
int main()
{
int i,j,len,k;
n=1;
cin>>s[n];
while(s[n][0]!='0')
{
n++;
cin>>s[n];
}
n--;
for(i=1;i<=n;i++)
{
len=s[i].size();
int x;
int y;
x=int(s[i][0]-'a'+1);
y=int(s[i][len-1]-'a'+1);
a[x][y]=1;
}
//弗洛伊德算法
for(k=1;k<=26;k++) // 注意这层循环要放在最外面,我以前就经常搞混
for(i=1;i<=26;i++)
for(j=1;j<=26;j++) //遍历整个图
if(a[i][k]==1 && a[k][j]==1) //中转
a[i][j]=1; //表示点(i,k)与点(k,j)有路径,所以赋值为一
if(a[2][13]==1)
cout<<"Yes";
else
cout<<"No";
return 0;
}