P3953 [NOIP2017 提高组] 逛公园

NOIP2017提高组 逛公园

f[u][i]表示1~u的距离为其最短路+i的方案数,如果有0环则标记inf=1
dp时使用在反图上记忆化搜索并使用是否在栈中判断0环

点击查看代码
#include <queue>
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
const int N = 1e5 + 5, M = 4e5 + 5, K = 55;
int T, n, m, k, p, h1[N], h2[N], e[M], w[M], nxt[M], idx;
int dist[N], f[N][K]; bool st[N], inf, in_stk[N][K], vis[N][K];
void add(int *h, int a, int b, int c) {
    e[++ idx] = b, w[idx] = c, nxt[idx] = h[a], h[a] = idx;
}
void Dijkstra() { // 求出最短路
    typedef std::pair<int, int> PII;
    std::priority_queue<PII, std::vector<PII>, std::greater<PII> > heap;
    memset(dist + 1, 0x3f, n << 2), memset(st + 1, 0, n);
    heap.push({dist[1] = 0, 1});
    while(heap.size()) {
        int u = heap.top().second; heap.pop();
        if(st[u]) continue;
        st[u] = true;
        for(int i = h1[u]; i; i = nxt[i]) {
            int v = e[i];
            if(dist[v] > dist[u] + w[i])
                heap.push({dist[v] = dist[u] + w[i], v});
        }
    }
}
int dp(int u, int x) {
    if(in_stk[u][x]) return inf = true, 0; // 在栈中
    if(vis[u][x]) return f[u][x];
    in_stk[u][x] = vis[u][x] = true;
    f[u][x] = 0;
    for(int i = h2[u]; i; i = nxt[i]) {
        int v = e[i], x2 = dist[u] + x - w[i] - dist[v]; // x2为需要的x
        if(0 <= x2 && x2 <= k)
            f[u][x] += dp(v, x2), f[u][x] >= p && (f[u][x] -= p);
        if(inf) return 0;
    }
    if(u == 1 && !x) f[u][x] = 1; // 初始条件
    in_stk[u][x] = false;
    return f[u][x];
}
int main() {
    scanf("%d", &T);
    while(T --) {
        scanf("%d%d%d%d", &n, &m, &k, &p), idx = 0;
        memset(h1 + 1, 0, n << 2), memset(h2 + 1, 0, n << 2);
        for(int i = 0, a, b, c; i < m; i ++)
            scanf("%d%d%d", &a, &b, &c), add(h1, a, b, c), add(h2, b, a, c);
        Dijkstra(), inf = false;
        for(int i = 1; i <= n; i ++) memset(vis[i], 0, k + 1);
        int res = 0;
        for(int x = 0; x <= k && !inf; x ++) {
            for(int i = 1; i <= n; i ++) memset(in_stk[i], 0, k + 1); // 清空栈
            res += dp(n, x), res >= p && (res -= p);
        }
        if(inf) puts("-1");
        else printf("%d\n", res);
    }
    return 0;
}
posted @ 2022-09-29 14:05  azzc  阅读(28)  评论(0编辑  收藏  举报