任意两点间的最短路问题(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]);
}