跑路[最短路+DP+倍增]

跑路

链接:洛谷---跑路

题意:给定一张有向图,每条边的边权是1。如果一条路径是\(2^k\)那么可以视为1.求1到n的最短路

解法:
看到\(2^k\)我们可以考虑倍增处理。
定义这样一个bool数组\(G[i][j][k]\)表明点i是否可以通过\(2^k\)步到点j。
定义\(dis[i][j]\)是i到j的路径长度。
如果\(G[i][j][k]\)为true,将dis[i][j更新为1。

最后再跑最短路。

code:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <vector>
#include <deque>
#include <bitset>
#include <map>
#include <string>
#include <stack>
using namespace std;
#define lowbit(x) x&-x
#define ll long long
#define dob double
#define For(i,s,n) for(ll i = s;i <= n;i++)
#define mem0(a) memset(a,0,sizeof a)
#define gcd(a,b) __gcd(a,b)
const int N = 55;
const double eps = 1e-6;
const ll mod =  998244353;
const int inf = 0x3f3f3f3f;
const int maxn = 1e4+50;
void read(int &res){
    char c;bool flag = true;
    while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;res=c-'0';
    while((c=getchar())>='0'&&c<='9')res=res*10+c-'0';res*=flag;
}
int n,m;
int dis[N][N],dp[N][N][65];
//dis[i][j]表示i到j的距离,dp[i][j][k]表示i到j可不可以用2^k的步数走到
//dp[i][j][k] = dp[i][t][k-1]&&dp[t][j][k-1];
void init(){
    for(int k = 1;k <= 64;k++){
        for(int i = 1;i <= n;i++){
            for(int t = 1;t <= n;t++){
                for(int j = 1;j <= n;j++){
                    if(dp[i][t][k-1]&&dp[t][j][k-1])
                    dp[i][j][k] = dis[i][j] = 1;
                }
            }
        }
    }
}
void floyd(){
    for(int k = 1;k <= n;k++){
        for(int i = 1;i <= n;i++){
            for(int j = 1;j <= n;j++){
                dis[i][j] = min(dis[i][j],dis[i][k]+dis[k][j]);
            }
        }
    }
}
int main(){
    ios::sync_with_stdio(false);
    cin>>n>>m;
    memset(dp,false,sizeof dp);
    memset(dis,0x3f3f3f3f,sizeof dis);
    while(m--){
        int a,b;
        cin>>a>>b;
        dis[a][b] = dp[a][b][0] = true;
    }
    init();
    floyd();
    cout<<dis[1][n]<<endl;
    return 0;
}
posted @ 2021-04-23 08:22  Paranoid5  阅读(64)  评论(0编辑  收藏  举报