题目链接:http://poj.org/problem?id=3613
很好的一道题目,求在一个无向图上,经过n条边的两点之间的最短路。
推荐看 IOI国家集训队2008 俞华程《矩阵乘法在信息学中的应用》 和 Matrix67<十个利用矩阵乘法解决的经典题目>的文章。
首先我们在求无向图上求任意两点间有多少条路径的时候是通过矩阵相乘来求的,即A^2矩阵上A[i][j]表示i->j长度为2的路劲有多少条,然后看Floyd的状态转移方程:f[i][j]=Min{ f[i][k]+f[k][j] | 0<k<n },是不是跟矩阵相乘很像,因此我们改造想到改造矩阵乘法,把矩阵A*B相乘改为一个Floyd相乘的过程,那么就是经过n条边的最短路了。因为N很大,所以用二分优化,复杂度O(n^3lgn)。
1 //STATUS:C++_AC_125MS_1204KB 2 #include<stdio.h> 3 #include<stdlib.h> 4 #include<string.h> 5 #include<math.h> 6 #include<iostream> 7 #include<string> 8 #include<algorithm> 9 #include<vector> 10 #include<queue> 11 #include<stack> 12 using namespace std; 13 #define LL __int64 14 #define pii pair<int,int> 15 #define Max(a,b) ((a)>(b)?(a):(b)) 16 #define Min(a,b) ((a)<(b)?(a):(b)) 17 #define mem(a,b) memset(a,b,sizeof(a)) 18 #define lson l,mid,rt<<1 19 #define rson mid+1,r,rt<<1|1 20 const int N=210,M=1000000,INF=0x3f3f3f3f,MOD=1999997; 21 const LL LLNF=0x3f3f3f3f3f3f3f3fLL; 22 const double DNF=100000000; 23 24 int f[N*10],w[N][N]; 25 int nt,n,m,s,t; 26 struct Matrix{ 27 int ma[N][N]; 28 Matrix friend operator * (const Matrix a,const Matrix b){ 29 Matrix ret; 30 mem(ret.ma,0x3f); 31 int i,j,k; 32 for(k=0;k<n;k++) 33 for(i=0;i<n;i++) 34 for(j=0;j<n;j++) 35 if(a.ma[i][k]+b.ma[k][j]<ret.ma[i][j]) 36 ret.ma[i][j]=a.ma[i][k]+b.ma[k][j]; 37 return ret; 38 } 39 }mta,mtb; 40 41 int pow(int k) 42 { 43 mem(mtb.ma,0x3f); 44 for(int i=0;i<n;i++)mtb.ma[i][i]=0; 45 for(;k;k>>=1){ 46 if(k&1)mtb=mtb*mta; 47 mta=mta*mta; 48 } 49 return mtb.ma[f[s]][f[t]]; 50 } 51 52 int main() 53 { 54 // freopen("in.txt","r",stdin); 55 int i,a,b,c; 56 while(~scanf("%d%d%d%d",&nt,&m,&s,&t)) 57 { 58 n=0; 59 mem(f,-1); 60 mem(mta.ma,0x3f); 61 for(i=0;i<m;i++){ 62 scanf("%d%d%d",&c,&a,&b); 63 if(f[a]==-1)f[a]=n++; 64 if(f[b]==-1)f[b]=n++; 65 mta.ma[f[a]][f[b]]=mta.ma[f[b]][f[a]]=Min(mta.ma[f[a]][f[b]],c); 66 } 67 68 printf("%d\n",pow(nt)); 69 } 70 return 0; 71 }