2014 Super Training #10 G Nostop --矩阵快速幂
原题: FZU 2173 http://acm.fzu.edu.cn/problem.php?pid=2173
一开始看到这个题毫无头绪,根本没想到是矩阵快速幂,其实看见k那么大,就应该想到用快速幂什么的,况且n<=50,可以用矩阵来表示图。
1.为什么能用矩阵快速幂呢?
原理:
原始矩阵m[][]中,m[u][v]代表u到v的花费,求矩阵的k次幂后,此时m[u][v]代表,从u走向b经过v步的最少花费
注意此时矩阵的相乘应该写成:
m[a][b]=min(m[a][1]+m[1][b],...m[a][n]+m[n][b]) ,即取最小值而非相加。
2.为什么呢?
m的1次方,无疑是正确的。
m的2次方
此时(m[a][b])^2=min(m[a][1]+m[1][b],..m[a][n]+m[n][b]),就是枚举a经过1到n点再到b的最少花费,就是a经过两步到达b的最少花费
归纳法:
如果(m[a][b])^i代表了a走i步到达b的最少花费,则m^(i+1)=min((m[a][1])^i+m[1][b],...(m[a][n])^i+m[n][b])
所以可以这样做。
(借鉴nothing的博客)
代码:
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <cstdlib> #include <algorithm> #define Mod 1000000007 #define lll __int64 using namespace std; #define N 6007 struct Matrix { lll m[55][55]; }; int n,h,k; Matrix Mul(Matrix a,Matrix b) { Matrix c; memset(c.m,-1,sizeof(c.m)); for(int i=0;i<n;i++) for(int j=0;j<n;j++) { for(int k=0;k<n;k++) { if(a.m[i][k]!=-1&&b.m[k][j]!=-1) { if(c.m[i][j] == -1) c.m[i][j] = a.m[i][k]+b.m[k][j]; else c.m[i][j] = min(c.m[i][j],a.m[i][k]+b.m[k][j]); } } } return c; } Matrix fastm(Matrix a,int n) { if(n == 1) return a; Matrix res = fastm(a,n/2); res = Mul(res,res); if(n&1) res = Mul(res,a); return res; } Matrix MPow(Matrix a,int n) //第二种写法 { Matrix res = a; n--; while(n) { if(n&1) res = Mul(res,a); n>>=1; a = Mul(a,a); } return res; } int main() { int t,i,j,k; int u,v; lll w; Matrix A,ans; scanf("%d",&t); while(t--) { scanf("%d%d%d",&n,&h,&k); memset(A.m,-1,sizeof(A.m)); for(i=0;i<h;i++) { scanf("%d%d%I64d",&u,&v,&w); u--,v--; if(A.m[u][v] == -1) A.m[u][v] = w; else A.m[u][v] = min(A.m[u][v],w); } ans = MPow(A,k); printf("%I64d\n",ans.m[0][n-1]); } return 0; }
作者:whatbeg
出处1:http://whatbeg.com/
出处2:http://www.cnblogs.com/whatbeg/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
更多精彩文章抢先看?详见我的独立博客: whatbeg.com