有向图拓扑排序

P1113杂务

题目描述

John的农场在给奶牛挤奶前有很多杂务要完成,每一项杂务都需要一定的时间来完成它。比如:他们要将奶牛集合起来,将他们赶进牛棚,为奶牛清洗乳房以及一些其它工作。尽早将所有杂务完成是必要的,因为这样才有更多时间挤出更多的牛奶。当然,有些杂务必须在另一些杂务完成的情况下才能进行。比如:只有将奶牛赶进牛棚才能开始为它清洗乳房,还有在未给奶牛清洗乳房之前不能挤奶。我们把这些工作称为完成本项工作的准备工作。至少有一项杂务不要求有准备工作,这个可以最早着手完成的工作,标记为杂务11。John有需要完成的nn个杂务的清单,并且这份清单是有一定顺序的,杂务k(k>1)k(k>1)的准备工作只可能在杂务11至k-1k−1中。
写一个程序从11到nn读入每个杂务的工作说明。计算出所有杂务都被完成的最短时间。当然互相没有关系的杂务可以同时工作,并且,你可以假定John的农场有足够多的工人来同时完成任意多项任务。

请添加图片描述

思路:当看到这种题目上说明有前驱的问题一般用拓扑排序解决。
一般拓扑排序共有四个主要步骤:
1.初始化队列,将入度为 0 的节点放入队列。
2.取出队首,遍历其出边,将能够到达的点入度减一,同时维护答案数组。
3.若在此时一个点的入度变为 0,那么将其加入队列。
4.回到第二步,直到队列为空。

这个题的答案就是在不连通的点和连通块中前驱最多的点当中取max,所以维护一个答案数组即可。
拓扑排序ACcode:

#include<queue>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1e6+10;
int n,ans;
int a[N];

int f[N];//答案数组
int in[N];//记录入度
queue<int>q;//队列用来存入度为0的点

int h[N],e[N],ne[N],idx;//邻接表存图,数组要开点数*边数大小

void add(int a,int b)
{
    
    
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
    in[b]++;
}

void topsort()
{
    
    
    for(int i=1;i<=n;i++)
        if(in[i]==0)
        {
    
    
            f[i]=a[i];
            q.push(i);
        }
    while(!q.empty())
    {
    
    
        int u=q.front();
        q.pop();
        for(int i=h[u];i!=-1;i=ne[i])
        {
    
    
            int j=e[i];
            in[j]--;
            if(in[j]==0)q.push(j);
            f[j]=max(f[j],f[u]+a[j]);
        }
    }
}

int main()
{
    
      
    cin>>n;
    memset(h,-1,sizeof h);
    for(int i=1;i<=n;i++)
    {
    
    
        int x;
        cin>>x>>a[x];
        int t;
        while(cin>>t)
        {
    
    
            if(t==0)break;
            add(t,x);
        }
    } 
    topsort();
    for(int i=1;i<=n;i++)ans=max(ans,f[i]);
    cout<<ans<<endl;  
    return 0;
}

其实这个还可以通过模拟的方法来写,代码量也比较小 巩固好拓扑排序可以用模拟写一下
ACcode

#include<iostream>
#include<algorithm>
using namespace std;

const int N = 1e4+10;

int n,ans[N];

int main()
{
    
    
    cin>>n;
    for(int i=1;i<=n;i++)
    {
    
    
        int id,len,t;
        cin>>id>>len;
        int vis=0;//用来标记最大的前驱
        while(cin>>t&&t)
        {
    
    
            if(ans[t]>ans[vis])vis=t;
        }
        ans[id]=len+ans[vis];
    }
    sort(ans+1,ans+n+1);
    cout<<ans[n]<<endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Stephen_Curry___/article/details/126366784
今日推荐