最短路 Floyd-Warshall算法 详细介绍

来源:互联网 发布:淘宝推广公司 编辑:程序博客网 时间:2024/04/30 11:15

任意两点间的最短路问题(Floyd-Warshall算法)

在我们只使用顶点0-k和i,j的情况下,记i到j的最短路长度为d[k+1][i][j];

那么当k=-1时,就是一个顶点都不用,直接从i到j,那么d[0][i][j]=cost[i][j];

接下来就可以把只使用顶点0-k的问题转化成只使用0-k-1顶点的问题上。

 

一共有2种情况,(1)不经过顶点k的情况:d[k][i][j]=d[k-1][i][j];

                           (2)通过顶点k的情况: d[k][i][j]=d[k-1][i][k]+d[k-1][k][j];

那么组合起来就是:d[k][i][j]=min(d[k-1][i][j],d[k-1][i][k]+d[k-1][k][j]);

/**********************************************************************************************************/

我们可以发现可以省掉一维d[i][j]=min(d[i][j],d[i][k]+d[k][j]);(滚粗数组)

那么问题来了,为什么可以省掉一维呢?

回想之前做0-1背包问题的时候,dp[i+1]][j]表示从0到i这i+1个物品中选出总重量不超过j的物品时

总价值的最大值。那么递推式可以表示为:

for(i=0;i<n;i++)

for(j=w;j>=w[i];j--)

if(j>w[i])      dp[i+1][j]=dp[i][j];(不能选第i个物品,因为其重量w[i]超过了j)

else            dp[i+1][j]=max(dp[i][j],dp[i][j-w[i]]+v[i]);(可以选第i个)

这时dp[i+1][j]都是由dp[i][N]上一行数据推来的,而这时N<=j,改变的都是dp[i+1][j]而dp[i+1][N]没有变

所以当去掉一维dp[j]=max(dp[j],dp[j-w[i]]+v[i])时,当计算dp[j]的时候,dp[j-w[i]]=dp[i][j-w[i]],不影响结果。可以省掉一维

/***************************************************************************************************************************/

看这道题,如果省掉一维,d[k][i][j]=min(d[k-1][i][j],d[k-1][i][k]+d[k-1][k][j]);

                                               d[i][j]=min(d[i][j],d[i][k]+d[k][j])

    当计算d[i][j]时 这时d[i][k]不一定=d[k-1][i][k];而是=d[k][i][k](可能之前已经算完了d[i][k]);

    同理d[k][j]未必=d[k-1][k][j];

那为什么可以省掉一维呢? 

 如果d[i][k]不等于d[k-1][i][k];    而是=d[k][i][k]  也就是等于=min(dp[k-1][i][k],dp[k-1][i][k]+dp[k-1][k][k]);        

 但是大家可以发现dp[k-1][k][k]=0;   所以dp[i][k]=min(dp[k-1][i][k],dp[k-1][i][k])=dp[k-1][i][k];不影响结果。                                      

int d[N][N]; //d[u][v]表示边e=(u,v)的权值(不存在时设为INF,但是d[i][i]=0)
int v; //顶点数
void warshall_Floyd(void)
{
     for(k=0;k<v;k++)
        for(i=0;i<v;i++)
            for(j=0;j<v;j++)
               d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
}

1 0
原创粉丝点击