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