P3953 逛公园 [dp]

逛公园

题目描述见链接 .


color{red}{正解部分}

首先 DjiDji 求出从 11 节点到所有节点的 最短路,

F[i,j]F[i, j] 表示从 11ii 路径长度为最短路长度加 jj 长度的方案数,

F[i,j]=F[to,disi+jwtoidisto]F[i, j] = sum F[to, dis_i + j - w_{to ightarrow i} -dis_{to}],


color{red}{实现部分}

发现状态转移的顺序有些麻烦, 于是从 NN 号节点开始 记忆化搜索,

若现在在更新 F[i,j]F[i, j], 而又搜到了 F[i,j]F[i, j], 则可以判断有 无穷解 .

#include<bits/stdc++.h>
#define reg register
#define se second
#define fi first
typedef std::pair <int, int> pr;

const int maxn = 100005;
const int inf = 0x3f3f3f3f;

int read(){
        char c;
        int s = 0, flag = 1;
        while((c=getchar()) && !isdigit(c))
                if(c == '-'){ flag = -1, c = getchar(); break ; }
        while(isdigit(c)) s = s*10 + c-'0', c = getchar();
        return s * flag;
}

int N;
int M;
int K;
int mod;
int num0;
int dis[maxn];
int cnt[maxn];
int head[maxn];
int F[maxn][55];

bool vis[maxn];
bool used[maxn][55];

struct Edge{ int nxt, to, w; } edge[maxn*3], E[maxn*3];

void Add(int from, int to, int w){ edge[++ num0] = (Edge){ head[from], to, w }; head[from] = num0; }

void Dij(){
        std::priority_queue <pr, std::vector<pr>, std::greater<pr> > Q;
        for(reg int i = 1; i <= N; i ++) dis[i] = inf, vis[i] = 0;
        Q.push(pr(0, 1)); dis[1] = 0;
        while(!Q.empty()){
                int ft = Q.top().se; Q.pop();
                if(vis[ft]) continue ; vis[ft] = 1;
                for(reg int i = head[ft]; i; i = edge[i].nxt){
                        int to = edge[i].to;
                        if(dis[to] > dis[ft] + edge[i].w){
                                dis[to] = dis[ft] + edge[i].w;
                                Q.push(pr(dis[to], to));
                        }
                }
        }
}

bool FLAG;
int DFS(int k, int a){
        if(FLAG) return 0;
        if(a > K || a < 0) return 0;
        if(k == 1 && !a) return 1;
        if(used[k][a]) return FLAG=1;
        if(~F[k][a]) return F[k][a];
        used[k][a] = 1; int s = 0;
        for(reg int i = head[k]; i; i = edge[i].nxt){
                int to = edge[i].to;
                s = (s + DFS(to, dis[k]+a-edge[i].w-dis[to])) % mod;
        }
        used[k][a] = 0;
        return F[k][a] = s;
}

void Work(){
        N = read(), M = read(), K = read(), mod = read();
        for(reg int i = 1; i <= N; i ++) head[i] = 0; num0 = 0;
        for(reg int i = 1; i <= M; i ++){
                int x = read(), y = read(), c = read();
                Add(x, y, c);
                E[i].nxt = x, E[i].to = y, E[i].w = c;
        }
        Dij();
        for(reg int i = 1; i <= N; i ++)
                for(reg int j = 0; j <= K; j ++) F[i][j] = -1;
        for(reg int i = 1; i <= N; i ++) head[i] = 0; num0 = 0;
        for(reg int i = 1; i <= N; i ++)
                for(reg int a = 0; a <= K; a ++) used[i][a] = 0;
        for(reg int i = 1; i <= M; i ++) Add(E[i].to, E[i].nxt, E[i].w);
        int Ans = 0; FLAG = 0; 
        for(reg int a = 0; a <= K && !FLAG; a ++) Ans = (Ans + DFS(N, a)) % mod;
        if(FLAG) return printf("-1
"), void();
        printf("%d
", Ans);
}

int main(){ //多测不清空,爆零两行泪 .
           // 无解----------------------
        freopen("park.in", "r", stdin);
        freopen("park.out", "w", stdout);
        int T = read();
        while(T --) Work();
        return 0;
}
原文地址:https://www.cnblogs.com/zbr162/p/11822392.html