题意:
求无向图s,t点间经过L条边的最短路。
思路:
矩阵连乘求图中任意两点间的最短路不经常用,因为复杂度是N^3logN的,但这种算法对最短路径经过的路径数的描述却非常清晰,尤其当需经过路径L比较大而顶点数N比较小的时候,N^3logL就比较可观了,求最短路径的特殊矩阵乘法满足结合律,可以幂乘加速。很有意思的是:把两个mul函数中的k循环放到i,j之外后整个算法就变成了倍增floyd算法(倍增floyd每次不用min(g[i][j],g[i][k]+G[k][j])更新g[i][j]有别于floyd算法),结果复杂度都一样。理解倍增floyd有助于理解floyd中动态规划的特点。
代码:
//poj 3613
//sepNINE
#include <iostream>
#include <map>
using namespace std;
const int maxN=512;
int g[maxN][maxN];
int ans[maxN][maxN];
int tmp[maxN][maxN];
map<int,int> mymap;
int n;
void mul1()
{
int i,j,k;
for(i=1;i<=n;++i)
for(j=1;j<=n;++j){
tmp[i][j]=INT_MAX;
for(k=1;k<=n;++k)
if(ans[i][k]!=-1&&g[k][j]!=-1)
tmp[i][j]=min(tmp[i][j],ans[i][k]+g[k][j]);
}
for(i=1;i<=n;++i)
for(j=1;j<=n;++j)
ans[i][j]=tmp[i][j]==INT_MAX?-1:tmp[i][j];
return ;
}
void mul2()
{
int i,j,k;
for(i=1;i<=n;++i)
for(j=1;j<=n;++j){
tmp[i][j]=INT_MAX;
for(k=1;k<=n;++k)
if(g[i][k]!=-1&&g[k][j]!=-1)
tmp[i][j]=min(tmp[i][j],g[i][k]+g[k][j]);
}
for(i=1;i<=n;++i)
for(j=1;j<=n;++j)
g[i][j]=tmp[i][j]==INT_MAX?-1:tmp[i][j];
return ;
}
int main()
{
int i,L,m,s,e;
memset(g,-1,sizeof(g));
scanf("%d%d%d%d",&L,&m,&s,&e);
n=0;
while(m--){
int w,a,b;
scanf("%d%d%d",&w,&a,&b);
if(mymap[a]==0) mymap[a]=++n;
if(mymap[b]==0) mymap[b]=++n;
g[mymap[a]][mymap[b]]=g[mymap[b]][mymap[a]]=w;
}
memset(ans,-1,sizeof(ans));
for(i=1;i<=n;++i)
ans[i][i]=0;
while(L){
if(L%2==1)
mul1();//ans=ans*g;
mul2();//g=g*g;
L=L/2;
}
printf("%d",ans[mymap[s]][mymap[e]]);
}