Codeforces Round #374 (Div. 2) C. Journey(dp)

题目

n(n<=5e3)个点,m(m<=5e3)条边的有向图,保证无重边,

第i条边有一个权值ti(1<=ti<=1e9),代表经过这条边的时间,

给定一个T(1<=T<=1e9),要求在不超过T的时间下,从点1走到点n

输出满足条件的路径中,路径中经过的节点个数最多的路径,

输出长度,及路径途径哪些节点,题目保证最短路一定有解

思路来源

https://blog.csdn.net/aozil_yang/article/details/52714708

题解

dp[i][j]代表从1节点出发,当前走到节点i,途径j个节点的最小代价,

则满足dp[n][ans]<=T的最大ans即为所求,

pre[i][j]代表从1节点出发,当前走到节点i,途径j个节点时,i节点的前驱

找出ans后,倒序寻找前驱,再顺序输出结果即可

代码

#include<bits/stdc++.h>
using namespace std;
const int N=5e3+5;
const int INF=0x3f3f3f3f;
int n,m,T;
int dp[N][N],pre[N][N];
int u,v,w;
int ans,res[N],cnt;
struct node
{
	int u,v,w;
	void read()
	{
		scanf("%d%d%d",&u,&v,&w);
	}
}e[N];
int main()
{
	scanf("%d%d%d",&n,&m,&T);
	for(int i=1;i<=m;++i)
	{
		e[i].read();
	}
	memset(dp,INF,sizeof dp);
	dp[1][1]=0;
	for(int i=2;i<=n;++i)
	{
		for(int j=1;j<=m;++j)
		{
			u=e[j].u;v=e[j].v;w=e[j].w; 
			if(dp[v][i]>dp[u][i-1]+w)
			{
				dp[v][i]=dp[u][i-1]+w;
				pre[v][i]=u; 
			}
		}
	}
	for(int i=n;i>=1;--i)
	{
		if(dp[n][i]<=T)
		{
			ans=i;
			break;
		}
	}
	printf("%d\n",ans);
	for(int i=n;i!=1;i=pre[i][ans--])
	res[cnt++]=i;
	res[cnt++]=1;
	for(int i=cnt-1;i>=0;--i)
	printf("%d%c",res[i]," \n"[!i]);
	return 0;
}
发布了467 篇原创文章 · 获赞 53 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/Code92007/article/details/101122105