洛谷 P1613 跑路(Floyd,倍增)&& 【模板】 Floyd

传送门


解题思路

g[i][j][k]表示i到j这个点有没有长度为2^k的路径,若有为1,若没有为0。答案可以由g[i][x][k-1]&&g[x][j][k-1]更新(Floyd传递闭包)。

倍增求一遍后,把所有g[i][j][k] = 1 的 i j之间连一条长度为1的边(因为可以一步到达)。

然后在新图上做一遍最短路求一遍即可。

小小的眼睛里充满了大大的疑惑:

  • 与dp有啥关系……冲着dp标签去的
  • 只是一道绿题?感觉某些蓝题都比这个简单(看来我还是太菜了)

AC代码

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cmath>
 4 #include<cstdio>
 5 #include<cstring>
 6 using namespace std;
 7 int n,m,dis[55][55];
 8 bool g[55][55][70];
 9 int main()
10 {
11     memset(dis,0x3f,sizeof(dis));
12     cin>>n>>m;
13     for(int i=1;i<=m;i++){
14         int u,v;
15         scanf("%d%d",&u,&v);
16         g[u][v][0]=1;
17         dis[u][v]=1;
18     }
19     for(int lxl=1;lxl<=64;lxl++){
20         for(int i=1;i<=n;i++){
21             for(int j=1;j<=n;j++){
22                 for(int k=1;k<=n;k++){
23                     g[i][j][lxl]=max(g[i][j][lxl],g[i][k][lxl-1]&&g[k][j][lxl-1]);
24                 }
25                 if(g[i][j][lxl]) dis[i][j]=1;
26             }
27         }
28     }
29     for(int k=1;k<=n;k++){
30         for(int i=1;i<=n;i++){
31             for(int j=1;j<=n;j++){
32                 dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
33             }
34         }
35     }
36     cout<<dis[1][n];
37     return 0;
38 }

//发现博客里没有Floyd的题?那就当个Floyd板子吧QAQ

//那既然是板子,就补充一句,Floyd一定要先枚举中间点k。

posted @ 2020-10-20 23:31  尹昱钦  阅读(135)  评论(0编辑  收藏  举报