Sicily 1308. Dependencies among J

图论

今天训练的题目,题意:有一些工作要做必须等某些工作做完了才能开始,每个工作也要花费时间去做。输入先给出n,m,表示有n个工作,要求完成第m个工作的最短时间(工作从1到n标号),下面n行给出每个工作的信息,每行第一个数表示做这个工作要多少时间,后面可能有1个或多个或0个数字,表示这个工作要在这些工作做完后才能动工。另外注意一点,同一个时刻只能做一个人工作,不能同时进行多个工作

这题一开始看错,以为又是关键路径,敲了模板发现wa,才看到那句话,同一个时间只能做一个工作不能同时进行多个工作,因为这个条件,这道题可以说和关键路径就毫无关系了。后来想不出方法,在队友的提醒下想到了正解。

其实我们只要知道第m个工作前面有多少个工作,每个工作的时间只能被计算一次

好像1-->2-->3-->4 ,   2--->4 ,  1-->5--->4

在4只能的点有1,2,3,5,这些点都影响了4,但是俺路径来算,要按点来算,每个点的时间只能算一次,所以完成4的最早时间就是

T[4]=val[1]+val[2]+val[3]+val[5]+val[4];  (做它本身也需要时间)

但是怎么知道m前面有哪些点呢,队友提示,图是有向图而且保证了无环,那么只要把所有有向边取反,从m点出发,遍历一次图即可,因为从m出发能去到的点,在取反前应该是这些点能去到m,而且遍历的话就能保证每个点只被访问一次,时间也就只计算了一次

用了vector建图,如果手动模拟邻接表的话时间会快些

#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
#define N 10010

vector<int>a[N];
int val[N];
int n,m;
bool vis[N];
int res;

void dfs(int u)
{
    vis[u]=true;
    res += val[u];
    int size=a[u].size();
    for(int i=0; i<size; i++)
        if(!vis[ a[u][i] ])
            dfs(a[u][i]);
    return ;
}

void solve()
{
    res=0;
    memset(vis,0,sizeof(vis));
    dfs(m);
    printf("%d\n",res);
}

int main()
{
    //freopen("input.txt","r",stdin);
    while(scanf("%d",&n)!=EOF && n)
    {
        scanf("%d",&m);
        for(int i=1; i<=n; i++)
            a[i].clear();
        for(int i=1; i<=n; i++)
        {
            char ch;
            int u,v;
            scanf("%d",&val[i]);
            ch=getchar();
            if(ch=='\n') continue;
            while(1)
            {
                scanf("%d",&u);
                a[i].push_back(u);
                ch=getchar();
                if(ch=='\n')
                    break;
            }
        }
        solve();
    }
    return 0;
}
原文地址:https://www.cnblogs.com/scau20110726/p/3018726.html