【BZOJ1706】relays 奶牛接力跑
阿新 • • 發佈:2019-01-22
解析:
矩陣快速冪。
首先將起點終點離散化降至以內。
考慮最裸的狀態轉移,令表示經過條邊從到的最短路長度,就有:
這樣直接轉移複雜度是的考慮去掉部分後實際上就是一個矩陣乘法,那麼相當於是求初始矩陣的次方,矩陣快速冪即可。
總結:若發現遞推式很像矩陣乘法,並且滿足結合律,那麼就可以大膽地用矩陣乘法/矩陣快速冪求解。
程式碼:
#include <bits/stdc++.h>
using namespace std;
const int Max=105;
int n,m,s,t,k,rev[Max*10];
struct matrix{int a[Max][Max];}ans,v;
inline matrix mul(const matrix&a,const matrix&b)
{
matrix c;
memset(c.a,0x3f,sizeof(c.a));
for (int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
c.a[i][j]=min(c.a[i][j],a.a[i][k]+b.a[k][j]);
return c;
}
inline void solve()
{
while(k)
{
if(k&1) ans=mul(ans,v);
k>>=1,v=mul(v,v);
}
}
int main()
{
memset(v.a,0x3f,sizeof(v.a));
memset(ans. a,0x3f,sizeof(ans.a));
scanf("%d%d%d%d",&k,&m,&s,&t);
for(int i=1,a,b,c;i<=m;i++)
{
scanf("%d%d%d",&c,&a,&b);
if(!rev[a]) rev[a]=++n;
if(!rev[b]) rev[b]=++n;
v.a[rev[a]][rev[b]]=v.a[rev[b]][rev[a]]=min(v.a[rev[b]][rev[a]],c);
}
for(int i=1;i<=n;i++) ans.a[i][i]=0;
solve();
printf("%d",ans.a[rev[s]][rev[t]]);
return 0;
}