CF-721C DAG图拓扑排序+费用DP

比赛的时候写了个记忆化搜索,超时了。

后来学习了一下,这种题目应该用拓扑排序+DP来做。

dp[][]保存走到[第i个节点][走过j个点]时所用的最短时间。

pre[][]用前驱节点求路径

然后遍历一下dp[n][],求满足t范围的最大下标。

#include <iostream>
#include <queue>
#include <cstdio>
#include <vector>
#include <stack>
#define N 5050
#define INF 1000000200
//#define LL long long int
using namespace std;
int n,m,sum,cnt,flag,t;
int deg[N];
vector<int> g[N],f[N];//保存后继节点
int dp[N][N],pre[N][N];//保存走到第i个点,走过j个点时所用时间
struct cmp
{
    bool operator()(int a,int b)
    {
        return a>b;
    }
};
void topoSort()
{
    priority_queue<int,vector<int>,cmp> q;
    for(int i=1;i<=n;i++)
        if(deg[i]==0)
            q.push(i),deg[i]--;
    while(!q.empty())
    {
        //if(q.size()>1) 可用于判断是否充分排序。
        //如果有多个入度为0的同时入队,说明他们之间没有明确的排序条件。
        int u=q.top();
        q.pop();
        sum--;//可用于判断是否有冲突,如果有冲突,就会导致两者或者已上的节点入度无法降为0
        for(int i=0;i<g[u].size();i++)
        {
            int e=g[u][i];
            deg[e]--;
            for(int j=2;j<=n;j++)
            {
                //cout<<dp[u][i]<<' '<<e<<endl;
                if(dp[e][j]>dp[u][j-1]+f[u][i])
                    dp[e][j]=dp[u][j-1]+f[u][i],pre[e][j]=u;
            }
        }
        for(int i=1;i<=n;i++)
            if(deg[i]==0)
                q.push(i),deg[i]--;
    }
}
void ini()
{
    for(int i=0;i<=n;i++)
        deg[i]=0,flag=0,g[i].clear(),f[i].clear();
    cnt=0,sum=n;
    for(int i=0;i<=n;i++)
        for(int j=0;j<=n;j++)
            dp[i][j]=t+100,pre[i][j]=-1;
    dp[1][1]=0;
}
void add(int u,int v,int fe)
{
    deg[v]++;
    g[u].push_back(v);
    f[u].push_back(fe);
}
int main() {
    //cin.sync_with_stdio(false);
    scanf("%d%d%d",&n,&m,&t);
        ini();
        for(int i=0;i<m;i++)
        {
            int u,v,fe;
            scanf("%d%d%d",&u,&v,&fe);
            add(u,v,fe);
        }
        //cout<<dp[1][2]<<endl;
        topoSort();
        int Maxp=-1;
        for(int i=1;i<=n;i++)
        {
            if(dp[n][i]<=t)
                Maxp=i;//求最大合法经过点数
        }
        stack<int> ss;
        int pos=n,lef=Maxp;
        cout<<Maxp<<endl;
        while(pos!=-1)
        {
            ss.push(pos);
            pos=pre[pos][lef],lef--;
        }
        //ss.push(1);
        while(ss.size()>1)
            cout<<ss.top()<<' ',ss.pop();
        cout<<ss.top()<<endl;
        ss.pop();
    
    return 0;
}

 

posted @ 2016-10-13 18:28  Luke_Ye  阅读(552)  评论(0编辑  收藏  举报