P1113 杂务

显然地,本题中各项工作是有一定的依赖条件的,也就是说我们在进行工作 X 之前可能需要先进行一些其他的工作。

而完成工作 X 所需的时间和所有 X 所依赖的工作完成的时间的最大值有关。(应该还好理解吧)

在这道题中,我们可以列出一个简单的 DP 转移方程:

$$f_i=\max\{pre_i\}+a_i$$

其中 \(f_i\) 为从最开始到进行完第 \(i\) 项任务所需的时间, \(pre_i\)\(i\) 号结点的前驱数组, \(a_i\) 为做第 \(i\) 件事所需的时间。

但是,我们如果直接进行 dfs 遍历,可能会出现一个问题:在我们计算 \(f_i\) 的时候,还存在没有计算过的 \(pre_i\),从而导致结果计算错误。
那么,我们在计算的时候,应该确保在计算一个结点 \(u\) 时,所有与连向它的点都已经被计算过

而实现这一过程就利用到:拓扑排序

const int N=1e5+10;
vector<int> g[N];
int din[N];
int cost[N];
int f[N];
int n;

int topo()
{
    queue<int> q;
    int res=0;
    for(int i=1;i<=n;i++)
        if(!din[i])
        {
            q.push(i);
            f[i]=cost[i];
            res=max(res,f[i]);
        }

    while(q.size())
    {
        int t=q.front();
        q.pop();

        for(int i=0;i<g[t].size();i++)
        {
            int j=g[t][i];
            f[j]=max(f[j],f[t]+cost[j]);
            res=max(res,f[j]);

            if(--din[j] == 0) q.push(j);
        }
    }
    return res;
}

int main()
{
    cin>>n;

    for(int i=1;i<=n;i++)
    {
        int a,t;
        cin>>a>>cost[i];
        int x;
        while(cin>>x && x)
            g[x].push_back(a),din[a]++;
    }

    cout<<topo()<<endl;

    //system("pause");
}
posted @ 2020-09-01 11:43  Dazzling!  阅读(125)  评论(0编辑  收藏  举报