P3953 逛公园

Posted qdscwyy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P3953 逛公园相关的知识,希望对你有一定的参考价值。

Description

策策同学特别喜欢逛公园。公园可以看成一张N个点M条边构成的有向图,且没有 自环和重边。其中1号点是公园的入口,N号点是公园的出口,每条边有一个非负权值, 代表策策经过这条边所要花的时间。

策策每天都会去逛公园,他总是从1号点进去,从N号点出来。

策策喜欢新鲜的事物,它不希望有两天逛公园的路线完全一样,同时策策还是一个 特别热爱学习的好孩子,它不希望每天在逛公园这件事上花费太多的时间。如果1号点 到NN号点的最短路长为dd,那么策策只会喜欢长度不超过d+K的路线。

策策同学想知道总共有多少条满足条件的路线,你能帮帮它吗?

为避免输出过大,答案对PP取模。

如果有无穷多条合法的路线,请输出-1。

Solution

参考了题解 P3953 【逛公园】可能是长沙一位大佬的题解.

没有零环

首先考虑没有零环的情况, 这时候只需要用一个类似于最短路计数的做法.
首先求出 1 号点到所有点的最短路.
(f(u,j))表示从一到(u)的所有路径中小于(dis_u+j)的有多少条.
(f(u,j))可以转移到(f(v,dis_u + c + j - dis_v))
如果存在边((u, v))且边权为(c)的话.

这样的话需要先更新(dis)小的点.

对了, 注意转移的枚举顺序, 先枚举(j), 再枚举$$

优化

需要优化的呀!
因为会超时的呀!

所以我就优化了一上午

  • 内存池开好
  • 手写pair<int, int>
  • zkw线段树优化dijkstra
  • 读入优化

ZKW线段树参考了这里

Code

#include <math.h>
#include <queue>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
const int inf = 0x3f3f3f3f;
const int N = 100003;
using namespace std; 

namespace {
    struct Node {
        int v; int id;
        Node() { }
        Node(int _value): v(_value) {}
        Node(int _, int __) : v(_), id(__) {}
        bool operator < (const Node& o) const {
            return v < o.v;
        }
    };
    class Heap {
      private:
        Node *d; int n;
      public:
        Heap(int _MaxN) {
            n = 1 << (1 + (int) (log(_MaxN) / log(2.0)));
            d = new Node[n << 1];
            for (int i = 1; i <= n + n - 1; i++)
                d[i] = Node(inf, i - n + 1);
        }
        ~Heap() { }
        inline int top_pos() { 
            return d[1].id; 
        }
        inline void modify(int pos, int s) {
            int p = pos + n - 1;
            d[p].v = s;
            while (p) {
                p >>= 1,
                d[p] = min(d[(p << 1) + 1], d[p << 1]);
            }
        }
    };
}
struct Edge {
    int v, c; Edge* nxt;
    Edge() : nxt(nullptr) {}
    Edge(int pos, int __, Edge* ___) : v(pos), c(__), nxt(___) {}
} *head[N], pool[1000005];
int cnt;
#define new_Edge(u, v, c) (pool[cnt] = Edge(u, v, c), &pool[cnt++])
#define AddEdge(u, v, c) head[u] = new_Edge(v, c, head[u])
int dis[N];

const int MAXIN = 1 << 22;
char IN[MAXIN], *SS = IN, *TT = IN;
#define gc() (SS == TT && (TT = (SS = IN) + fread(IN, 1, MAXIN, stdin), SS == TT) ? EOF : *SS++)
inline int read() {
    int now = 0; register char c = gc();
    for (; !isdigit(c); c = gc());
    for (; isdigit(c); now = now * 10 + c - '0', c = gc());
    return now;
}

struct Pair {
    int dis, id;
    Pair() {}
    Pair(int pos, int __) : dis(pos), id(__) {}
    bool operator < (const Pair& o) const {
        return dis > o.dis;
    }
};
void dijkstra(int n) {
    Heap* T = new Heap(n + 1);
    memset(dis, 0x3f, sizeof dis);
    dis[1] = 0, T->modify(1, 0);
    for (int i = 1; i <= n; i += 1) {
        int u = T->top_pos(); 
        T->modify(u, inf); 
        for (auto edge = head[u]; edge; edge = edge->nxt) {
            int v = edge->v; 
            if (dis[v] > dis[u] + edge->c)
                dis[v] = dis[u] + edge->c, 
                T->modify(v, dis[u] + edge->c);
        }
    }
}
int f[N][51];
Pair F[N];
int dp(int k, const int mod, int n) {
    for (int i = 1; i <= n; i += 1)
        F[i] = Pair(-dis[i], i);
    memset(f, false, sizeof f);
    sort(F + 1, F + n + 1);
    f[1][0] = 1;
    for (int j = 0; j <= k; j += 1) {
        for (int i = 1; i <= n; i += 1) {
            int u = F[i].id;
            if (not f[u][j]) continue;
            for (auto edge = head[u]; edge; edge = edge->nxt) {
                int v = edge->v, ly = dis[u] + j + edge->c - dis[v];
                if (ly <= k) f[v][ly] = (f[v][ly] + f[u][j]) % mod;
            }
        }
    }
    int res = 0;
    for (int i = 0; i <= k; i += 1)
        res = (res + f[n][i]) % mod;
    return res;
}

int main () {
    int T = read();
    while (T--) {
        int n, m, k, p;
        n = read(), m = read(), k = read(), p = read();
        for (int i = 1; i <= n; i += 1) head[i] = nullptr;
        for (int i = 0, u, v, c; i < m; i += 1) {
            u = read(), v = read(), c = read();
            AddEdge(u, v, c);
        }
        dijkstra(n);
        printf("%d
", dp(k, p, n));
    }
    return 0;
}

以上是关于P3953 逛公园的主要内容,如果未能解决你的问题,请参考以下文章

P3953 逛公园

[luogu P3953] [noip2017 d1t3] 逛公园

Luogu P3953NOIP2017逛公园最短路+拓扑排序+动态规划

P3953 NOIP2017 d1t3 逛公园

P3953 逛公园

[Luogu P3953] 逛公园 (最短路+拓扑排序+DP)