权重矩阵最小路径_最短路径和矩阵乘法

介绍

这里讲的顶点对之间的最短路径是基于动态规划在图中的实现。每一个循环都类似矩阵乘法,因此这个算法看起来就像是一直在做矩阵乘法。

实现

在这里我们用邻接矩阵表示法来表示一个图,因为相对邻接表来说,邻接矩阵表示要容易些,并且采用自底而下的算法来计算最短路径权重。

typedef int (*Metrix)[VERTEX_NUMBER];

void printfMatrix(Metrix graphmetrix)

{

for (int x = 0; x < VERTEX_NUMBER; ++ x)

{

for (int y = 0; y < VERTEX_NUMBER; ++ y)

{

cout << "\t" << graphmetrix[x][y] << " ";

}

cout << endl;

}

cout << endl;

}

这是输出一个图的矩阵表示法,其中的每个值表示当中两个顶点之间的权重值。

int getSentinel()

{

return 0x7fffffff;

}

Metrix entendShortestPaths(Metrix left, Metrix right)

{

const int n = VERTEX_NUMBER;

int *graph = new int[n * n];

Metrix c = (int(*)[n])graph;

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

{

for (int j = 0; j < n; ++ j)

{

c[i][j] = getSentinel();

for (int k = 0; k < n; ++ k)

{

if (getSentinel() != left[i][k] && getSentinel() != right[k][j])

{

c[i][j] = std::min(c[i][j], left[i][k] + right[k][j]);

}

}

}

}

return c;

}

在计算时,我们首先把结果矩阵里面的值均初始化为最大,然后再计算它和当前两个结点权重之间的最小值,返回的最小值就是两个顶点之间的最小权重。在这里,left[i][k]就是结点i->k的最短路径值,然后,right[k][j]就是k->j的最小权重值,把2个相加就是i->j的最小权重值。接着来看看矩阵乘法的算法:

Metrix squareMatrixMultiply(Metrix left, Metrix right)

{

const int n = VERTEX_NUMBER;

int *graph = new int[n * n];

Metrix c = (int(*)[n])graph;

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

{

for (int j = 0; j < n; ++ j)

{

c[i][j] = 0;

for (int k = 0; k < n; ++ k)

{

c[i][j] += left[i][k] * right[k][j];

}

}

}

return c;

}

是不是和上面的算法很相似呢。这里计算c[i][j]的值就是left矩阵的第i行的值乘以right的第j列的所有值的结果的总和。

然后,计算最短路径有2种方法,慢速的和快速的,其中快速的是在慢速的基础上做优化。先来看看慢速的如何计算:

Metrix slowAllPairsShortestPaths(Metrix graph)

{

const int n = VERTEX_NUMBER;

int *tmp = new int[n * n];

Metrix c = (int(*)[n])tmp;

memcpy(c, graph, n * n * sizeof(4));

for (int m = 1; m < n - 1; ++ m)

{

Metrix p = entendShortestPaths(c, graph);

delete [] c;

c = p;

printfMatrix(c);

}

return c;

}

我们在每次扩展最短路径的结果中,把返回的结果矩阵继续和原始矩阵做扩展,直到计算n-1次为止。而在这个算法上做的优化则是:因为我们的目的只是需要得出n-1次的最后结果,而不关心中间结果。所以我们可以每次进行m*2操作来让m的值进行递增,而不是m+1。

Metrix fasterAllPairsShortestPaths(Metrix graph)

{

const int n = VERTEX_NUMBER;

int *tmp = new int[n * n];

Metrix c = (int(*)[n])tmp;

memcpy(c, graph, n * n * sizeof(4));

int m = 1;

while (m < n - 1)

{

Metrix p = entendShortestPaths(c, c);

delete [] c;

c = p;

printfMatrix(c);

m *= 2;

}

return c;

}

我们可以来看看最短路径的图解过程:

慢速最短路径图解过程

而我们再来测试下慢速和快速的运行结果,也使用上图中一样的图:

int _tmain(int argc, _TCHAR* argv[])

{

copyright();

cout << getSentinel() << endl;

cout << "directed adjacency matrix: " << endl;

int graphmetrix[VERTEX_NUMBER][VERTEX_NUMBER] =

{

{0, 3, 8, 0x7fffffff, -4},

{0x7fffffff, 0, 0x7fffffff, 1, 7},

{0x7fffffff, 4, 0, 0x7fffffff, 0x7fffffff},

{2, 0x7fffffff, -5, 0, 0x7fffffff},

{0x7fffffff, 0x7fffffff, 0x7fffffff, 6, 0},

};

cout << "directed weight graph structure: " << endl;

for (int x = 0; x < VERTEX_NUMBER; ++ x)

{

cout << "vertex " << x + 1 << ";";

for (int y = 0; y < VERTEX_NUMBER; ++ y)

{

if (0 != graphmetrix[x][y])

{

cout << y + 1 << " ";

}

}

cout << endl;

}

cout << "origin: " << endl;

printfMatrix(graphmetrix);

cout << "slow algorithm: " << endl;

Metrix c = slowAllPairsShortestPaths(graphmetrix);

delete [] c;

cout << "faster algorithm: " << endl;

c = fasterAllPairsShortestPaths(graphmetrix);

delete [] c;

return 0;

}

慢速最短路径运行结果

快速最短路径运行结果

从结果中可以看出,快速的比慢速的要快,而且这是在结点数量少的情况,如果是结点数量多的情况,优化效果是很显示的,计算量要少很多。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值