[NOIp2017]逛公园

Description

Luogu3953
求与最短路相差不超过k的路径条数。

Solution

不难想到DP,一个点的路径条数是它能到的点的路径条数之和。
考虑一个点(i),设(path(S,i) + dis(i, T) = dis(S,T) + k),其中(path)是当前走过的路径,(dis)是最短路径,考虑一条边(e(i,j,w)),此时(path(S,j)+dis(j,T) = path(S,i) + w + dis(j, T) = dis(S, T) + k - dis(i, T) + w + dis(j, T)),所以超出最短路的长度变化了(-dis(i,T)+w+dis(j,T)),这样就可以转移了。具体看代码。

Code

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>

const int N = 100010;
const int M = 400010;

int n, m, k, P;
int hd[N], to[M], nxt[M], w[M], fl[M], cnt;
int dis[N], vis[N];
int insta[N][55], f[N][55];
struct node {
    int p, d;
    node (int a=0, int b=0) : p(a), d(b) {}
    bool operator< (const node& x) const { return d > x.d; }
};

void adde(int x, int y, int z, int f) {
    cnt++;
    to[cnt] = y; nxt[cnt] = hd[x]; w[cnt] = z;
    fl[cnt] = f;
    hd[x] = cnt;
}

void dij() {
    std::priority_queue<node> q;
    q.push(node(n, dis[n]=0));
    while (!q.empty()) {
        node x = q.top(); q.pop();
        if (vis[x.p]) continue;
        vis[x.p] = 1;
        for (int i = hd[x.p]; i; i = nxt[i]) if (!vis[to[i]] && fl[i] == 1) {
            if (dis[to[i]] > dis[x.p] + w[i]) {
                q.push(node(to[i], dis[to[i]] = dis[x.p] + w[i]));
            }
        }
    }
}

int dfs(int p, int x) {
    if (x < 0) return 0;
    if (insta[p][x]) return -1;
    if (f[p][x]) return f[p][x];
    int ans = 0;
    if (p == n) ans = 1;
    insta[p][x] = 1;
    for (int i = hd[p]; i; i = nxt[i]) if (fl[i] == 0) {
        int tmp = dfs(to[i], x - w[i] - dis[to[i]] + dis[p]);
        if (tmp == -1) return -1;
        ans = (ans + tmp) % P;
    }
    f[p][x] = ans % P;
    insta[p][x] = 0;
    return ans % P;
}

void init() {
    memset(vis, 0, sizeof vis);
    memset(insta, 0, sizeof insta);
    memset(f, 0, sizeof f);
    memset(dis, 0x3f, sizeof dis);
    memset(hd, 0, sizeof hd);
    cnt = 0;
}

int main() {
    int t;
    scanf("%d", &t);
    while (t--) {
        init();
        scanf("%d%d%d%d", &n, &m, &k, &P);
        for (int i = 1, x, y, z; i <= m; ++i) {
            scanf("%d%d%d", &x, &y, &z);
            adde(x, y, z, 0);
            adde(y, x, z, 1);
        }
        dij();
        printf("%d
", dfs(1, k) % P);
    }
    return 0;
} 
原文地址:https://www.cnblogs.com/wyxwyx/p/noip201713.html