POJ3613 Cow Relays
题目链接:POJ3613 Cow Relays
题目大意:
一张图有 \(T\) 条边,边两个端点的序号 \(\in [1,1000]\) ,求起点 \(S\) 到 \(E\) 恰好经过 \(N\) 条边的最短路。
\(1\leq T\leq 100\) , \(1\leq N\leq 1000000\)
思路:
经典题,点的数量最多为 \(2T\) ,先离散化,考虑矩阵乘法:
设 \(M*M\) 的矩阵 \(A^k\) , \((A^k)[i,j]\) 为从 \(i\) 到 \(j\) 恰好经过 \(k\) 条边的最短路长度,那么应该有:
\[(A^{a+b})[i,j]=\min_{1\leq k\leq M}\{(A^a)[i,k]+(A^b)[k,j]\}
\]
其中 \(A^1\) 就是邻接矩阵, \((A^N)[s][e]\) 即为答案。
注意到这个过程满足结合律,其实就是将加法改为取 \(min\) 的矩阵乘法,那么我们就可以矩阵快速幂了,时间复杂度 \(O(T^3logN)\) 。
细节:
- 矩阵定义时可以在外面套一个结构体,这样就不用纠结数组指针之类的问题了,可以直接引用和复制。
Code:
#include<iostream>
#include<algorithm>
#include<vector>
#include<cstring>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=b;i>=a;i--)
#define lb lower_bound
#define T 205
#define hash Hash
#define Inf 0x3f3f3f3f
using namespace std;
struct edge{
int len,u,v;
}E[T];
struct matrix{
int a[T][T];
void init(){
rep(i,0,T-1)rep(j,0,T-1)a[i][j]=Inf;
}
};
matrix mat,opt,c;
int n,t,s,e;
int hash[T];
void mul(matrix &a,matrix b){
c.init();
rep(i,0,t-1)rep(j,0,t-1)rep(k,0,t-1)
c.a[i][j]=min(c.a[i][j],a.a[i][k]+b.a[k][j]);
a=c;
}
int main(){
cin>>n>>t>>s>>e;
rep(i,0,t-1){
cin>>E[i].len>>E[i].u>>E[i].v;
hash[2*i]=E[i].u,hash[2*i+1]=E[i].v;
}
sort(hash,hash+2*t);
int m=unique(hash,hash+2*t)-hash;
opt.init();
rep(i,0,t-1){
int u=lb(hash,hash+m,E[i].u)-hash;
int v=lb(hash,hash+m,E[i].v)-hash;
opt.a[u][v]=opt.a[v][u]=E[i].len;
}
mat=opt;
n--;
for(;n;n>>=1){
if(n&1)mul(mat,opt);
mul(opt,opt);
}
s=lb(hash,hash+m,s)-hash,e=lb(hash,hash+m,e)-hash;
cout<<mat.a[s][e];
return 0;
}