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;
}
posted @ 2018-11-04 17:05  Zolrk  阅读(188)  评论(0编辑  收藏  举报