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 }
View Code

猜你喜欢

转载自www.cnblogs.com/nopartyfoucaodong/p/9723575.html