floyd算法,又称插点法,多用于求给定加权图任意两点间的最短路径,比较简洁易懂的算法,但是复杂度高。用于解决点少的情况很适用。
核心代码:
for(int k=1; k<=n; k++)
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
if(maze[i][j] > maze[i][k] + maze[k][j])
maze[i][j] = maze[i][k] + maze[k][j];
三层循环的作用是暴力枚举所有中点,起点和终点,分别用 k , i , j 表示。
必须注意的是外层循环必须为 k 的枚举,考虑算法更新边权的方式,用起点到中点到终点的边权与起点到终点的边权取小。
~ 如果 k 写在第三层,也就是在确定了 i 和 j 的位置之后枚举 k,这样每组 i 和 j 只会枚举一次 k ,而 k 处的点都是没有更新过的,所以用 k 枚举一次来确定当前的 maze[ i ] [ j ] 是不能得到最优解的。
~ 如果 k 写在第二层,也就是在确定了 i 和 k的位置之后枚举 j,看似可以确定了 k 的最优解,但是同理,j 出的所有点也都是没有更新过的,所以用 j 枚举一次来确定 k 的最优解也是不能得到最优解的。
~ 如果 k 写在最外层,可以确定任意一组 i j 以任意一个点作为 k 的最优解,也就是可以求得任意一组 i j 的最优解。
~ 理解循环关键是要了解状态转移的原理。
例题 HDU 1690
#include"iostream"
#include"cmath"
#include"cstdio"
#include"string"
#include"cstring"
#define MAXN 1005
#define INF 0xfffffffffff
using namespace std;
int poi[MAXN];
long long maze[MAXN][MAXN];
int n, m, t, l1, l2, l3, l4, c1, c2, c3, c4;
void init()
{
for(int i=1; i <= n; i++)
for(int j=1; j <= n; j++)
{
if(i == j) maze[i][j] = 0;
else maze[i][j] = INF;
}
}
int main(void)
{
scanf("%d",&t);
int T = 1;
while(t--)
{
scanf("%d%d%d%d%d%d%d%d", &l1, &l2, &l3, &l4, &c1, &c2, &c3, &c4);
cin>>n>>m;
init();
for(int i=1; i<=n; i++) scanf("%d",&poi[i]);
for(int i=1; i<=n; i++)
{
for(int j=i+1; j <= n; j++)
{
int len = abs(poi[i] - poi[j]);
if(len>0 && len<=l1) maze[i][j] = maze[j][i] = c1;
else if(l1 maze[i][k] + maze[k][j])
maze[i][j] = maze[i][k] + maze[k][j];
printf("Case %d:\n",T++);
while(m--)
{
int st, en;
cin>>st>>en;
if(maze[st][en] != INF)
printf("The minimum cost between station %d and station %d is %lld.\n",st,en,maze[st][en]);
else
printf("Station %d and station %d are not attainable.\n", st, en);
}
}
}