洛谷P1613 跑路

传送门啦

分析:

这个题看很多人都在用Floyd和倍增的方法来做的。

那我就用spfa来跑最短路吧

a[i][j][k]:表示从i到j是否存在长2^k的边。

预处理的时候就将这些边赋值成1 (长2^k的边)(再补充一下:这些边用1s就能走完)

注意一下:

预处理的时候k循环在最外层,因为要所有的从u到v长度为2^k的边,然后赋值成1.

而打标记的时候k放在了最后一层循环上,因为要把u到v边上的情况全部试一遍。。好像不太清楚。。

就是u到v的边的值我们不确定,所以都枚举试一遍。 (从0开始,被这个卡了好几次)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int maxn = 55;

long long n,m,u,v,a[maxn][maxn][65]; 
long long f[maxn][maxn];
long long dis[maxn];
bool vis[maxn];

void spfa(int s){
    queue<int > q;
    for(int i=1;i<=n;i++){
        dis[i] = 1e9;
    }
    q.push(s);
    dis[s] = 0;
    vis[s] = 1;
    while(!q.empty()){
        int cur = q.front();
        q.pop();
        vis[cur] = 0;
        for(int v=1;v<=n;v++)
          if(f[cur][v] && dis[v] > dis[cur] + f[cur][v]){
            dis[v] = dis[cur] + f[cur][v];
            if(vis[v] == 0){
              vis[v]=1;
              q.push(v);
            }
        }
    }
}

int main(){
    scanf("%lld%lld",&n,&m);
    for(int i=1;i<=m;i++){
        scanf("%lld%lld",&u,&v);
        a[u][v][0] = 1;
    }
    for(int k=1;k<=64;k++)
      for(int j=1;j<=n;j++)
        for(int u=1;u<=n;u++)
          for(int v=1;v<=n;v++)
            if(a[u][j][k-1] && a[j][v][k-1])
              a[u][v][k]=1;

    for(int u=1;u<=n;u++)
      for(int v=1;v<=n;v++)
        for(int k=0;k<=64;k++)
          if(a[u][v][k]){
             f[u][v]=1;
             break;
          }
    spfa(1);
    printf("%lld",dis[n]);
    return 0;
}

最后wustdio给我介绍了一种矩阵加速的写法。。

顺风不浪,逆风不怂。
原文地址:https://www.cnblogs.com/Stephen-F/p/9864757.html