江苏徐州邀请赛 I题 类矩阵快速幂

题意:
即一个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进行判断>>>>>>>>>>

收获:对快速幂的应用更加了解深入,类乘法快速幂,所需要的条件是需要满足结合律>>>>>>

猜你喜欢

转载自www.cnblogs.com/vainglory/p/9141551.html
今日推荐