Floyd 算法

问题描述:给定一个带权图(可以有负权),求任意两点间的最短路。

算法过程:

本质是一个动态规划的过程。

G中n个顶点的编号为1到n。令c[i][j][k]表示从i 到j 的最短路径的长度,其中中间顶点不超过k。如果G中包含边<i, j>,则c[i][j][0] =边<i, j> 的长度;否则c[i][j][0]= +∞。c[i][j][n] 则是从i 到j 的最短路径的长度。

对于任意的k>0,通过分析可以得到:中间顶点不超过k的i到j的最短路径有两种可能:该路径含或不含中间顶点k。若不含,则该路径长度应为c[i][j[k-1],否则长度为c[i][k][k-1] +c [k][j][k-1]。c[i][j][k]是两者中的最小值。

状态转移方程:c[i][j][k]=min{ c[i][j[k-1], c[i][k][k-1]+c [k][j][k-1]},k>0。

这样,问题便具有了最优子结构性质,可以用动态规划方法来求解。

for(int k=1;k<=n;k++)
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            dist[i][j][k]=MIN(dist[i][j][k-1], dist[i][k][k-1]+dist[k][j][k-1]);

简化即得如下。

具体实现:

void floyd(int n)//floyd算法
{
    for (int k = 1; k <= n; k++)
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= n; j++)
                if (t[i][k]+t[k][j] < t[i][j])
                {
                    t[i][j] = t[i][k]+t[k][j]; 
                    path[i][j] = k;
                }
}
  1. for循环不可以改成i,j,k。
  2. 如需记录路径需增加path,path[i][j] = k表示,i经过k到达j;再递归path[i][k],path[k][i]即可

算法复杂度:O(n^3)

例:POJ 1125 Stockbroker Grapevine

View Code
//POJ 1125 Stockbroker Grapevine
//floyd算法

#include <iostream>
#include <memory.h>
#include <cstdlib>
#define MAX_N 100
#define INF 100000
using namespace std;

int t[MAX_N][MAX_N];//Note time to send message

int max_time(int n, int i)//让所有人收到消息所要时间
{
    int j;
    int max = -INF;
    for (j = 0; j < n; j++)
        if (t[i][j] > max)
            max = t[i][j];
    return max;
}

void floyd(int n)//floyd算法,DP
{
    int k, i, j;
    for (k = 0; k < n; k++)
        for (i = 0; i < n; i++)
            for (j = 0; j < n; j++)
            {
                if (t[i][k]+t[k][j] < t[i][j])
                    t[i][j] = t[i][k]+t[k][j]; 
            }

}
int main(void)
{
    int ns;//number of stockbrokers
    int nc;//number of people can contact to
    int  min , maxtime_i, min_man;
    int i, j, k;
    while (cin >> ns, ns)
    {
        memset(t, 1, sizeof(t));//把t[][]全部置成足够大的整数
        for (i = 0; i < ns; i++)
            t[i][i] = 0;
        for (i = 0; i < ns; i++)
        {
            cin >> nc;
            for (j = 0; j < nc; j++)
            {
                cin >> k;
                cin >> t[i][k-1];
            }
        }
        floyd(ns);
        min = INF;
        for (i = 0; i < ns; i++)
        {
            maxtime_i = max_time(ns, i);//让所有人收到消息所要时间
            if(maxtime_i < min)
            {
                min = maxtime_i;
                min_man = i + 1;//记录当前最短时间的经纪人号码
            }
        }
        if (min >= MAX_N)//说明必定有人孤立
            cout << "disjoint" << endl;
        else
            cout << min_man << " " << min << endl;
    }
    return 0;
}

 

posted on 2012-12-12 12:19  澄哥  阅读(227)  评论(0编辑  收藏  举报

导航