zoukankan      html  css  js  c++  java
  • Luogu P3953 逛公园 (最短路+dp)

    Luogu P3953 逛公园 (最短路+dp)

    补题地址

    题意:

    一个有向图,找从1到n的长度在 d 到 d + k 之间的路径个数模 p 的值。(d是1到n的最短路,k,p由输入给出)。

    思路:

    首先想到dp[i][j]表示1到 i 距离为j的路径个数,那么dp[n][d] + ... + dp[n][d + k] 就是答案。但是数组开不了这么大,且复杂度不对。但dp的大方向应该不会错。

    我们注意到k很小,所以可以把dp二维 j 表示改为从1 到 i 距离小于d + j 的路径个数。这样就可以了。那么转移方程就是:

    [dp[u][j] = sum dp[v][(d[u] + j) - w - d[v]] ]

    其中d[i] 表示从i 到 n 的最短路,这个我们可以在原图的反向图上跑Dijkstra求出。那么 d[u]+ j 就是 u 到 n 点的距离,减 w 就是此时 v 到 n的距离,再减d[v] 就是 v 到 n的距离比v到 n的最短路d[v] 大的值,即dp数组二维的含义。

    我们可以从1点开始dfs,去计算结果,具体过程见代码。

    这里要注意这种情况:存在权值和为0的环时,路径可以无限在环上绕,有无限中路径,要输出-1。判断这种情况只需要开一个flag[][]数组,在一个点处理dp[u][j] 时,看会不会再处理一次dp[u][j], 如果再次处理说明转移过程中有个环且环的权值和为0。直接return -1。具体见代码。

    代码:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<map>
    #include<queue>
    #include<vector>
    #include<string>
    #include<bitset>
    #include<fstream>
    using namespace std;
    #define rep(i, a, n) for(int i = a; i <= n; ++ i);
    #define per(i, a, n) for(int i = n; i >= a; -- i);
    typedef long long ll;
    typedef pair<int,int> PII;
    const int N = 2e5 + 105;
    const int mod = 1e9 + 7;
    const double Pi = acos(- 1.0);
    const int INF = 0x3f3f3f3f; 
    const int G = 3, Gi = 332748118;
    ll qpow(ll a, ll b) { ll res = 1; while(b){ if(b & 1) res = (res * a) % mod; a = (a * a) % mod; b >>= 1;} return res; }
    ll gcd(ll a, ll b) { return b ? gcd(b, a % b) : a; }
    // bool cmp(int a, int b){return a > b;}
    //
    
    int n, m; int k, p;
    int head[N << 1], cnt = 0;
    int rhead[N << 1], rcnt =  0;
    int to[N << 1], nxt[N << 1]; int c[N << 1];
    int rto[N << 1], rnxt[N << 1]; int rc[N << 1];
    queue<int> q;
    int dp[N][60];
    bool flag[N][60];
    
    void add(int u, int v, int w){
        to[cnt] = v, c[cnt] = w, nxt[cnt] = head[u], head[u] = cnt ++;
        rto[rcnt] = u, rc[rcnt] = w, rnxt[rcnt] = rhead[v], rhead[v] = rcnt ++;
    }
    
    //Dijkstra
    int d[N << 1];
    void Dijkstra(int st)
    {
        priority_queue<PII, vector<PII>, greater<PII> > q;
        for(int i = 1; i <= n + 1; ++ i) d[i] = INF;
        d[st] = 0;
        q.push(PII(0, st));
        while(!q.empty()){
            int u = q.top().second; int w1 = q.top().first; q.pop();
            if(w1 != d[u]) continue;
            for(int i = rhead[u]; i != -1; i = rnxt[i]){
                int v = rto[i]; int w2 = rc[i];
                if(d[u] + w2 < d[v]){
                    d[v] = d[u] + w2;
                    q.push(PII(d[v], v));
                }
            }
        }
    }
    
    int dfs(int u, int t){
        if(t < 0 || t > k) return 0;
        if(flag[u][t]) return -1;
        if(dp[u][t]) return dp[u][t];
        flag[u][t] = 1;
        int sum = 0;
        for(int i = head[u]; i != -1; i = nxt[i]){
            int v = to[i]; int w = c[i];
            int tp = dfs(v, t + d[u] - w - d[v]);
            if(tp == -1) return -1;
            sum = (sum + tp) % p;
        }
        if(u == n && t == 0) sum ++;
        dp[u][t] = sum;
        flag[u][t] = 0;
        return sum;
    }
    
    int main()
    {
        int T;
        scanf("%d",&T);
        while(T --){
            scanf("%d%d%d%d",&n,&m,&k,&p);
            cnt = rcnt = 0;
            for(int i = 0; i <= n; ++ i) head[i] = rhead[i] = -1;
            memset(flag, false, sizeof(flag));
            memset(dp, 0, sizeof(dp));
    
            for(int i = 1; i <= m; ++ i){
                int x, y; int z; scanf("%d%d%d",&x,&y,&z);
                add(x, y, z);
            }
            Dijkstra(n);
            
            int res = 0; bool fl = 0;
            for(int i = 0; i <= k; ++ i){
                int tp = dfs(1, i);
                if(tp == -1){
                    fl = 1;
                    break;
                }
                res = (res + tp) % p;
            }
            if(fl) printf("-1
    ");
            else printf("%d
    ",res);
        }
        return 0;
    }
    
    
  • 相关阅读:
    布隆过滤器解决缓存穿透问题
    查询指定距离内的快递柜或者店铺
    各注册中心consul eureka 以及nacos的服务发现原理
    consul注册中心服务注册过程源码分析
    consul注册中心如何自动剔除下线服务
    svn执行reflash/cleanup报错wc.db解决办法
    第二章
    第一章 JVM和Java体系架构
    2、操作系统-中断
    1、操作系统-启动
  • 原文地址:https://www.cnblogs.com/A-sc/p/13746952.html
Copyright © 2011-2022 走看看