版权声明:转载请注明原出处啦QAQ(虽然应该也没人转载): https://blog.csdn.net/hzk_cpp/article/details/83097897
题目:POJ3613.
题目大意:给出一张图,然你求出经过N条边后,S到T的最短路.
这道题一开始觉得挺容易的,用f[i][j]表示从起点到点i经过j的最短路,不断更新就可以了.
但是突然发现数据巨大根本跑不过去...
然后就开始看书上的题解了...
书上居然要用矩阵乘法,好难写的要不我放弃吧...
书上说的思路就是先离散化,然后用floyd算法用f[i][j][k]表示从i到j的经过k条边的最短路.
那么我们将转移方程列出来:
然后我们会发现,每一次转移时用来更新的边权都是一样的,而且点的范围特别小,更新的次数特别多.
所以我们可以想到矩阵乘法刚好满足这几个性质,而且f其实就是一个矩阵!
那么其实f就是一个“广义矩阵乘法”,很明显广义矩阵乘法是满足结合律的,所以我们就可以用快速幂优化递推.时间复杂度,由于2P个点不一定能跑满,所以这个算法是能过的.
代码如下:
#include<iostream>
#include<cstdio>
using namespace std;
#define Abigail inline void
typedef long long LL;
const int P=1000,T=100,INF=(1<<29)-1;
int num[P+9],ord[P+9],top;
int s,t,x[T+9],y[T+9],v[T+9];
int n,m;
struct matrix{
int a[T*2+9][T*2+9],n,m;
matrix(){
n=m=0;
for (int i=0;i<T*2+9;i++)
for (int j=0;j<T*2+9;j++)
a[i][j]=INF;
}
matrix operator * (const matrix &p)const{
matrix tmp=matrix();
tmp.n=n;tmp.m=p.m;
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
for (int k=1;k<=p.m;k++)
tmp.a[i][k]=min(tmp.a[i][k],a[i][j]+p.a[j][k]);
return tmp;
}
}a;
matrix power(matrix a,int k){
matrix s=a;k--;
for (;k;k>>=1,a=a*a)
if (k&1) s=s*a;
return s;
}
Abigail into(){
scanf("%d%d%d%d",&n,&m,&s,&t);
for (int i=1;i<=m;i++){
scanf("%d%d%d",&v[i],&x[i],&y[i]);
num[x[i]]++;num[y[i]]++;
}
}
Abigail work(){
for (int i=1;i<=1000;i++)
if (num[i]) ord[i]=++top;
s=ord[s];t=ord[t];
for (int i=1;i<=m;i++)
a.a[ord[x[i]]][ord[y[i]]]=a.a[ord[y[i]]][ord[x[i]]]=min(a.a[ord[x[i]]][ord[y[i]]],v[i]);
a.n=a.m=top;
a=power(a,n);
}
Abigail outo(){
printf("%d\n",a.a[s][t]);
}
int main(){
into();
work();
outo();
return 0;
}