CF721C Journey 题解

题目给了我们一张 DAG,对于 DAG 常用的方法就是拓扑排序。

题目要求一条从 1 到 n n n 的路径, 点数尽量多但是距离不能超过 k k k,那么我们考虑 DP 解决这个问题。

f i , j f_{i,j} fi,j 表示从 1 开始经过 i i i 个点,到达 j j j 点的最短路径,那么首先满足最优性。

而拓扑排序的一条重要性质就是只有入度为 0 的点才能处理,恰好满足无后效性。

于是我们就可以设计出这样的状态转移方程:

f i + 1 , v = min ⁡ { f i , u + d i s u − > v ∣ u ∈ S } f_{i+1,v}=\min\{f_{i,u}+dis_{u->v}|u \in S\} fi+1,v=min{ fi,u+disu>vuS}

S S S 表示所有能够到达 u u u 的点集。

初始状态为 f 1 , 1 = 0 f_{1,1}=0 f1,1=0,其余为正无穷。

同时为了记录方案,我们还需要一个 g i , j g_{i,j} gi,j 表示当前状态是由哪个点转移而来的。

最后输出时,从大到小枚举 i ∈ [ 1 , n ] i \in [1,n] i[1,n],找到第一个 f i , n ≠ inf ⁡ f_{i,n} \ne \inf fi,n=inf 就输出答案以及方案。

代码:

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
const int MAXN = 5000 + 10;
int n, m, f[MAXN][MAXN], g[MAXN][MAXN], t, cnt[MAXN];
vector <int> Next[MAXN], Num[MAXN];

int read()
{
    
    
	int sum = 0, fh = 1; char ch = getchar();
	while (ch < '0' || ch > '9') {
    
    if (ch == '-') fh = -1; ch = getchar();}
	while (ch >= '0' && ch <= '9') {
    
    sum = (sum << 3) + (sum << 1) + (ch ^ 48); ch = getchar();}
	return sum * fh;
}

void topsort()
{
    
    
	queue <int> q;
	for (int i = 1; i <= n; ++i)
		if (!cnt[i]) q.push(i);
	while (!q.empty())
	{
    
    
		int x = q.front(); q.pop();
		for (int i = 0; i < Next[x].size(); ++i)
		{
    
    
			int u = Next[x][i], w = Num[x][i];
			for (int j = 1; j <= n; ++j)
			{
    
    
				if (f[j][x] == 0x3f3f3f3f) continue;
				if (f[j][x] + w > t) continue;
				if (f[j + 1][u] > f[j][x] + w) {
    
    f[j + 1][u] = f[j][x] + w; g[j + 1][u] = x;}
			}
			--cnt[u];
			if (cnt[u] == 0) q.push(u);
		}
	}
}

void print(int last, int now)
{
    
    
	if (last > 1) print(last - 1, g[last][now]);
	printf("%d ", now);
}

int main()
{
    
    
	n = read(), m = read(), t = read();
	for (int i = 1; i <= m; ++i)
	{
    
    
		int x = read(), y = read(), z = read(); cnt[y]++;
		Next[x].push_back(y), Num[x].push_back(z);
	}
	memset(f, 0x3f, sizeof(f));
	f[1][1] = 0;
	topsort();
	for (int i = n; i >= 1; --i)
		if (f[i][n] < 0x3f3f3f3f)
		{
    
    
			printf("%d\n", i);
			print(i, n); printf("\n");
			return 0;
		}
}

猜你喜欢

转载自blog.csdn.net/BWzhuzehao/article/details/113508373