1. 程式人生 > >Codeforces 721C Journey - DAGDP

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;
}