Codeforces 721C Journey - DAGDP

设dp[i][j]表示到第i个点一共经过j个点时的最小路径长度,按拓扑序转移就好了
考虑到到达第i个点并且目前走过的点数量固定时,显然不需要知道以前走的是哪些点,只要保证此时路径长度最短,就会得到更优的答案
注意到k不会超过int,所以数组不需要开longlong(开了会爆内存。。。)判断的时候强转就好了

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
using namespace std;
#define debug(x) cerr << #x << "=" << x << endl;
typedef long long ll;
const int MAXN = 5000 + 10;
int n,m,k,ans,edge_tot,tot;
int ind[MAXN],last[MAXN],pre[MAXN][MAXN],pla[MAXN];
int dp[MAXN][MAXN];
queue<int> q;
struct Edge{
    int u, v, w, to;
    Edge(){}
    Edge(int u, int v, int w, int to) : u(u), v(v), w(w), to(to) {}
}e[MAXN];
inline void add(int u, int v, int w) {
    e[++edge_tot] = Edge(u, v, w, last[u]);
    last[u] = edge_tot;
}
void topo() {
    for(int i=1; i<=n; i++)
        if(!ind[i]) q.push(i);
    while(!q.empty()) {
        int x = q.front();
        q.pop();
        for(int i=last[x]; i; i=e[i].to) {
            int v = e[i].v, w = e[i].w;
            ind[v]--;
            if(!ind[v]) q.push(v);
            for(int j=1; j<=n; j++) {
                if((ll)dp[x][j-1] + w <= k) {
                    if(dp[v][j] > dp[x][j-1] + w) {
                        dp[v][j] = dp[x][j-1] + w;
                        pre[v][j] = x;
                    }
                }
            }
        }
    }
}
int main() {
    scanf("%d%d%d", &n, &m, &k);
    for(int i=1; i<=m; i++) {
        int u, v, w;
        scanf("%d%d%d", &u, &v, &w);
        ind[v]++;
        add(u, v, w);
    }
    memset(dp, 0x3f, sizeof(dp));
    int temp_inf = dp[1][1];
    dp[1][1] = 0;
    pre[1][1] = 1;
    topo();
    for(int i=1; i<=n; i++) {
        if(dp[n][i] != temp_inf) ans = i;
    }
    printf("%d\n", ans);
    pla[++tot] = n;
    for(int i=ans; i>1; i--) {
        pla[++tot] = pre[pla[tot-1]][i];
    }
    for(int i=tot; i; i--) {
        printf("%d ", pla[i]);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Zolrk/p/9904697.html