poj3613 ACwing 345:Cow Relays--牛站

在这里插入图片描述

analysis

这是一个没有见过的模式:

  • 特征
  1. 求S到E恰好走过N条边的最短路
  2. 点数少到可以用邻接矩阵存
  • 解法

Floyd+矩阵快速幂

首先,若邻接矩阵A表示了两点间走过1条边的最短路,B表示了两点间走过2条边的最短路

那么有关系:

B [ i ] [ j ] = m i n ( A [ i ] [ k ] + A [ k ] [ j ] ) ( 1 &lt; = k &lt; = n ) B[i][j]=min(A[i][k]+A[k][j])(1&lt;=k&lt;=n) B[i][j]=min(A[i][k]+A[k][j])(1<=k<=n)

这样的话,我们继续推广这个关系可以得到:

若邻接矩阵A表示了两点间走过x条边的最短路,B表示了两点间走过k条边的最短路,C表示了两点间走过t条边的最短路,且k=x+t

那么:

B [ i ] [ j ] = m i n ( A [ i ] [ k ] + C [ k ] [ j ] ) ( 1 &lt; = k &lt; = n ) B[i][j]=min(A[i][k]+C[k][j])(1&lt;=k&lt;=n) B[i][j]=min(A[i][k]+C[k][j])(1<=k<=n)

如果我们换个方式写,设 A i A^i Ai邻接矩阵保存的是走过i条边后的两点之间的最短距离的话,那么

A i + j [ x ] [ y ] = m i n ( A i [ x ] [ k ] + A j [ k ] [ y ] ) A^{i+j}[x][y]=min(A^i[x][k] + A^j[k][y]) Ai+j[x][y]=min(Ai[x][k]+Aj[k][y])

最后的答案就是

A n [ S ] [ E ] A^n[S][E] An[S][E]

问题就转化为了:快速求出 A n A^n An数组

观察上面推广的式子,我们可以发现:

定义新运算"广义矩阵乘法"为

A i [ x ] [ y ] × A j [ x ] [ y ] = A i + j [ x ] [ y ] = m i n ( A i [ x ] [ k ] + A j [ k ] [ y ] ) A^{i}[x][y]\times A^{j}[x][y]=A^{i+j}[x][y]=min(A^i[x][k] + A^j[k][y]) Ai[x][y]×Aj[x][y]=Ai+j[x][y]=min(Ai[x][k]+Aj[k][y])

那么"广义矩阵乘法"满足结合律,也就是说:

( A i × A j ) × A k = A i × ( A j × A k ) (A^i\times A^j)\times A^k=A^i\times (A^j\times A^k) (Ai×Aj)×Ak=Ai×(Aj×Ak)

那么就可以对n进行二进制拆分, A n A^n An就可以像快速幂一样在logn的时间里求出来了

code

#include<bits/stdc++.h>
using namespace std;
#define loop(i,start,end) for(register int i=start;i<=end;++i)
#define anti_loop(i,start,end) for(register int i=start;i>=end;--i)
#define clean(arry,num) memset(arry,num,sizeof(arry))
#define ll long long
#define copy(arry1,arry2) memcpy(arry1,arry2,sizeof(arry1))
template<typename T>void read(T &x){
	x=0;char r=getchar();T neg=1;
	while(r>'9'||r<'0'){if(r=='-')neg=-1;r=getchar();}
	while(r>='0'&&r<='9'){x=(x<<1)+(x<<3)+r-'0';r=getchar();}
	x*=neg;
}
int T;
const int maxt=100+10;
int n;
const int maxn=1e6+10;
int nfp=0,S,E;
int G[maxt<<1][maxt<<1];
struct martix{
	int G[maxt<<1][maxt<<1];
	void clear_(){
		loop(i,1,200){
			loop(j,1,200){
				G[i][j]=0x3f3f3f3f;
			}
		}
	}
	void print_(int len){
		loop(i,1,len){
			loop(j,1,len){
				printf("%d ",G[i][j]);
			}
			printf("\n");
		}
		printf("\n");
	}
};
inline martix mutply(martix A,martix B,int len){
	martix ans;
	ans.clear_();
	loop(i,1,len){
		loop(j,1,len){
			loop(k,1,len)
				ans.G[i][j]=min(A.G[i][k]+B.G[k][j],ans.G[i][j]);
		}
	}
	return ans;
}
martix res;
martix sta;
inline void fastpower(int len,int t){
	--t;
	copy(res.G,G);
	copy(sta.G,G);
	//res.print_(len);
	//sta.print_(len);
	while(t){
		if(t&1){
			res=mutply(sta,res,len);
			//res.print_(len);
		}
		t>>=1;
		sta=mutply(sta,sta,len);
		//sta.print_(len);
	}
}
struct road{
	int xi;
	int yi;
	int wi;
}line[maxt];
map<int,int>M;
int main(){
	#ifndef ONLINE_JUDGE
	freopen("datain.txt","r",stdin);
	#endif
	read(n);
	read(T);
	read(S);
	read(E);
	loop(i,1,T){
		read(line[i].wi);
		read(line[i].xi);
		read(line[i].yi);
		if(M[line[i].xi]==0)
			M[line[i].xi]=++nfp;
		if(M[line[i].yi]==0)
			M[line[i].yi]=++nfp;
	}
	clean(G,0x3f);
	loop(i,1,T)
		G[M[line[i].yi]][M[line[i].xi]]=G[M[line[i].xi]][M[line[i].yi]]=line[i].wi;	
	fastpower(nfp,n);
	printf("%d\n",res.G[M[S]][M[E]]);
	return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AndrewMe8211

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值