题意:
即一个m个点的图,求走n步,所能获得的最大权值
n(2e5),m(100)
时间限制:2s,样例:10组
思路1:dp
dp[i][j]表示i步到达j所能获得的最大权值
for i=1:n
for j=1:m
for k=1:m
dp[i][j]=max(dp[i][j],dp[i][k]+v[k][j]);
复杂度为 n*m^2, 复杂度会爆的
思路2:
考虑下最短路中松弛的说法,我们定义为扩张
for i=1:m
for j=1:m
for k=1:m
f[i][j]=max(f[i][j],f[i][k]+v[k][j]);
每经历过1次 m^3的扩展相当于走了一步
走n步的时候相当于 扩展n次
复杂度即为 n*m^3
考虑该代码的形式,即v数组是不变的
考虑这个n能不能化简掉
楼上代码的形式很像矩阵乘法6666啊
考虑下快速幂的方法>>>因为固定起点是A,终点是B,走七步,那么结果一定等于max(f A,3,j+f j,4,B)的结果
所以其满足结合律
能满足结合律的话,那么就一定能满足运用快速幂的形式,刚刚zzy大佬讲解的好精辟
66666>>>感谢大佬
#include<bits/stdc++.h> using namespace std; typedef long long ll; struct mat{ ll a[110][110]; mat(){memset(a,0,sizeof(a));} }; int n,m; mat multi(mat x,mat y){ mat res; for(int i=1;i<=m;i++) for(int j=1;j<=m;j++) for(int k=1;k<=m;k++) res.a[i][j]=max(res.a[i][j],x.a[i][k]+y.a[k][j]); return res; } mat pow_(mat a,int n){ mat res;mat tmp=a; while(n){ if(n&1) res=multi(res,tmp); tmp=multi(tmp,tmp); n>>=1; } return res; } int main(){ while(~scanf("%d%d",&n,&m)){ mat ans; for(int i=1;i<=m;i++) for(int j=1;j<=m;j++) scanf("%lld",&ans.a[i][j]); ans=pow_(ans,n-1); ll max_=0; for(int i=1;i<=m;i++) for(int j=1;j<=m;j++) max_=max(max_,ans.a[i][j]); printf("%lld\n",max_); } return 0; }
考虑下更通俗的题目,推广到所有的图,均可应用,前提是节点个数不应该超过200个,不然不能对其进行应用floyd型处理
记得zoj有道类似的题目
Mistwald(ZOJ3479) 其题目的意思是给出n*m个点,然后每个点会往其他的点移动,然后给定移动的方向点。求判断,在规定步数下,一定能到达终点输出t rue,不一定就maybe,否则就False。
同样的问题>>>>>>年轻是真的傻
总结:即在判断点的连通性,给定步数,问能否到达某个点,或者是说给定步数求最大路径的权值 >>在点数量范围能允许的情况下,可以运用floyd进行判断>>>>>>>>>>
收获:对快速幂的应用更加了解深入,类乘法快速幂,所需要的条件是需要满足结合律>>>>>>
原文地址:https://www.cnblogs.com/vainglory/p/9141551.html