Codeforces 721C: Journey DP+TopSort
Journey
题目链接:
http://codeforces.com/contest/721/problem/C
题意:
有个无环图,图中每条边有个权值(时间),求从点1走到点n途中最多可以经过的点的个数和路径(花费不超过t)
题解:
由于边和点都只有5000条,先拓扑排序一下,按tp完后的顺序跑一边DP就行了。
dp[i][j]为以点1为起点,点 i 为终点途经 j 个点所需要的最小花费。
代码
#include<stdio.h>
#include<vector>
#include<queue>
using namespace std;
const int N=5001;
const int inf=(1e9)+1;
vector<pair<int,int> >vec[N];
int in[N],poi[N],to[N][N];
int dp[N][N];
queue<int>que;
void solve()
{
int n,m,u,v,res,w,t;
scanf("%d%d%d",&n,&m,&t);
for(int i=1;i<=n;++i)
vec[i].clear(),in[i]=0;
while(m--)
{
scanf("%d%d%d",&u,&v,&w);
vec[u].push_back(make_pair(v,w));
in[v]++;
}
while(!que.empty())que.pop();
for(int i=1;i<=n;++i)
if(!in[i])que.push(i);
int tot=0;
while(!que.empty())
{
int f=que.front();
poi[++tot]=f;
que.pop();
for(int i=0;i<vec[f].size();++i)
{
v=vec[f][i].first;
in[v]--;
if(!in[v])que.push(v);
}
}
for(int i=1;i<=n;++i)
for(int j=0;j<=n;++j)
dp[i][j]=inf;
dp[1][0]=0;
for(int i=1;i<=n;++i)
for(int j=0;j<vec[poi[i]].size();++j)
{
u=poi[i];
v=vec[u][j].first;
w=vec[u][j].second;
for(int k=0;k<n;++k)
if(dp[u][k]!=inf&&dp[v][k+1]>dp[u][k]+w)
dp[v][k+1]=dp[u][k]+w,to[v][k+1]=u;
}
res=0;
for(int i=0;i<=n;++i)
if(dp[n][i]<=t)res=i;
tot=0,v=n;
printf("%d\n",res+1);for(int i=res;i>=1;--i)
poi[++tot]=to[v][i],v=to[v][i];for(int i=res;i>=1;--i)
printf("%d ",poi[i]);
printf("%d\n",n);
}
int main()
{
solve();
return 0;
}