Luogu P1613跑路【倍增】By cellur925
开始的思路:直接跑一遍最短路,得到最短路的那个值。然后把那个值进行一下二进制拆分,看能拆几次。(可能是受到了刚做过的题影响)
for(int i=30;i>=0;i--) { if((1<<i)>qwq) continue; //printf("%d\n",i); qwq-=(1<<i);ans++; }
(二进制拆分从大到小趋近)
但实际上貌似是审错题了...只有在两点最短距离为$2^k$时才能用加速器。那么我们就需要枚举所有点对,看他们的 距离是否为$2^k$,是的话才能向他们之间连一条边。由于输出的边距离都为$2^0$,所以可以直接连边。这部分是一个运用到$floyd$思想、倍增思想的判断dp,如果若两个点能以两段2的k-1次方的距离相互到达,那么两个点就能以2的k次方的距离相互到达。(引用dalao@ GoldenPotato )。
之后我们就跑一遍$floyd$即可(本题数据范围为50)
Code
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 5 using namespace std; 6 7 int n,m; 8 int dis[100][100]; 9 bool valid[100][100][40]; 10 11 int main() 12 { 13 scanf("%d%d",&n,&m); 14 memset(dis,0x3f,sizeof(dis)); 15 for(int i=1;i<=m;i++) 16 { 17 int x=0,y=0; 18 scanf("%d%d",&x,&y); 19 dis[x][y]=1;valid[x][y][0]=1; 20 } 21 for(int h=1;h<=30;h++) 22 for(int k=1;k<=n;k++) 23 for(int i=1;i<=n;i++) 24 for(int j=1;j<=n;j++) 25 if(valid[i][k][h-1]&&valid[k][j][h-1]) 26 valid[i][j][h]=1,dis[i][j]=1; 27 for(int k=1;k<=n;k++) 28 for(int i=1;i<=n;i++) 29 for(int j=1;j<=n;j++) 30 dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]); 31 printf("%d",dis[1][n]); 32 return 0; 33 }
独立意志与自由思想是必须争的,且须以生死力争。