洛谷 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。