BZOJ 1706. [usaco2007 Nov]relays 奶牛接力跑
边数不大,可以把点离散化,然后点数就只有 $200$
考虑 $dp$,设 $f[k][i][j]$ 表示走了 $k$ 步,从 $i$ 到 $j$ 的最小路程,发现转移可以倍增优化
$f[k][i][j]=min(f[k/2][i][j],f[k/2][i][l]+f[k/2][l][j])$
然后把 $f$ 滚动一下,做成矩阵,像矩阵快速幂一样搞就好了
这种方法好像有个名字叫倍增优化的 $floyd$?不太懂和 $floyd$ 有啥关系
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> using namespace std; typedef long long ll; inline int read() { int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f; } const int N=207; int n,m,S,T,cnt; struct Matrix { int a[N][N]; Matrix () { memset(a,0x3f,sizeof(a)); } inline Matrix operator * (const Matrix &tmp) const { Matrix res; for(int i=1;i<=cnt;i++) for(int j=1;j<=cnt;j++) for(int k=1;k<=cnt;k++) res.a[i][j]=min(res.a[i][j],a[i][k]+tmp.a[k][j]); return res; } }mp; Matrix ksm(Matrix x,int y) { Matrix res; for(int i=1;i<=cnt;i++) res.a[i][i]=0; while(y) { if(y&1) res=res*x; x=x*x; y>>=1; } return res; } int d[N],u[N],v[N],l[N]; int main() { n=read(),m=read(),S=read(),T=read(); for(int i=1;i<=m;i++) { l[i]=read(),u[i]=read(),v[i]=read(); d[++cnt]=u[i],d[++cnt]=v[i]; } sort(d+1,d+cnt+1); cnt=unique(d+1,d+cnt+1)-d-1; for(int i=1;i<=m;i++) { int x=lower_bound(d+1,d+cnt+1,u[i])-d,y=lower_bound(d+1,d+cnt+1,v[i])-d; mp.a[x][y]=mp.a[y][x]=l[i]; } mp=ksm(mp,n); S=lower_bound(d+1,d+cnt+1,S)-d; T=lower_bound(d+1,d+cnt+1,T)-d; printf("%d\n",mp.a[S][T]); return 0; }