问题描述:CodeForces 721C
思路:这是一个拓扑图,询问从1到n在T时间内最多能观光几个景点,并输出顺序,有边权。
这题是一个拓扑dp,考虑dp[i][j],到达i点时,观光了j个景点的最小时间
转移是这样对于一条边u -> v,dp[v][j] = min(dp[v][j],dp[u][j - 1] + dis[u][v]);
当时不会保存多个点的情况,用dp保存即可。
AC代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <math.h>
#include <string.h>
#include <queue>
#include <set>
#include <map>
#include <algorithm>
using namespace std;
const int maxn=5005;
const int inf=0x3f3f3f3f;
//int dis[maxn][maxn];
int vin[maxn];
struct edge
{
int v;
int cost;
edge(int a,int b)
{
v=a,cost=b;
}
};
typedef vector<edge> vec;
vec e[maxn];
int n,m,t;
struct node
{
int per;
int use;
} dp[maxn][maxn];
void tp()
{
queue<int>q;
for(int i=1; i<=n; i++)
if(vin[i]==0)
q.push(i);
while(!q.empty())
{
int u=q.front();
q.pop();
for(int i=0; i<e[u].size(); i++)
{
int v=e[u][i].v;
int cost=e[u][i].cost;
vin[v]--;
if(vin[v]==0)
q.push(v);
for(int j=1; j<=n; j++)
if(dp[v][j].use>dp[u][j-1].use+cost)
{
dp[v][j].use=dp[u][j-1].use+cost;
dp[v][j].per=u;
}
}
}
}
void show(int i,int j)
{
if(dp[i][j].per==-1)
{
printf("1 ");
return;
}
show(dp[i][j].per,j-1);
printf("%d ",i);
}
int main()
{
//freopen("intput.txt","r",stdin);
cin>>n>>m>>t;
int a,b,c;
for(int i=0; i<=n; i++)
for(int j=0; j<=n; j++)
{
dp[i][j].use=inf;
}
memset(vin,0,sizeof(vin));
for(int i=0; i<m; i++)
{
scanf("%d%d%d",&a,&b,&c);
e[a].push_back(edge(b,c));
vin[b]++;
}
//fill(tp,tp+maxn*maxn-1,inf);
dp[1][1].use=0;
dp[1][1].per=-1;
tp();
//for(int i=0;i<k;i++)cout<<topu[i]<<' ';
//cout<<endl;
for(int i=n; i>=1; i--)
{
if(dp[n][i].use<=t)
{
printf("%d\n",i);
show(n,i);
return 0;
}
}
return 0;
}