最短路与倍增的结合——跑路

跑路是一道简单题.

倍增和最短路的结合.

各大OJ上都有这道题,比如说:https://www.luogu.org/problemnew/show/P1613.

这道题仔细一分析,发现应该得先预处理再跑floyd.

我们得先预处理出一个bool数组dis[x][y][k],表示点x到点y之间的路是否有一条的权值为2^k.

那么大概就按照动态规划的思想,枚举一个中点u,dis[x][y][k]=dis[x][y][k]||dis[x][u][k-1]&&dis[u][y][k-1].

然后对一个存最短路的d数组初始化一波.

代码实现就这样:

inline void start(){
  rep(k,1,31)
    rep(i,1,n)
      rep(j,1,n)
        rep(p,1,n)
          dis[i][j][k]=dis[i][j][k]||dis[i][p][k-1]&&dis[p][j][k-1];
  memset(d,10,sizeof(d));
  rep(k,0,31)
    rep(i,1,n)
      rep(j,1,n)
        if (dis[i][j][k]) d[i][j]=1;
}

然后再跑一边floyd:

inline void floyd(){
  rep(k,1,n)
    rep(i,1,n)
      rep(j,1,n)
        d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
}

最后输出就好了.

AC代码如下:

扫描二维码关注公众号,回复: 391129 查看本文章
#include<bits/stdc++.h>
  using namespace std;
#define rep(i,j,k) for (int i=j;i<=k;i++)
int n,m;
bool dis[51][51][32]={0};
int d[51][51]={0};
inline void into(){
  scanf("%d%d",&n,&m);
  int x,y;
  rep(i,1,m){
    scanf("%d%d",&x,&y);
    dis[x][y][0]=1;
  }
}
inline void start(){
  rep(k,1,31)
    rep(i,1,n)
      rep(j,1,n)
        rep(p,1,n)
          dis[i][j][k]=dis[i][j][k]||dis[i][p][k-1]&&dis[p][j][k-1];
  memset(d,10,sizeof(d));
  rep(k,0,31)
    rep(i,1,n)
      rep(j,1,n)
        if (dis[i][j][k]) d[i][j]=1;
}
inline void floyd(){
  rep(k,1,n)
    rep(i,1,n)
      rep(j,1,n)
        d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
}
inline void work(){
  start();
  floyd();
}
inline void outo(){
  printf("%d\n",d[1][n]);
}
int main(){
  into();
  work();
  outo();
  return 0;
}

好了,手残地把i写成了1...

好吧.

OK就这样.

猜你喜欢

转载自blog.csdn.net/hzk_cpp/article/details/80148610