分析:
这个题看很多人都在用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给我介绍了一种矩阵加速的写法。。