zoukankan      html  css  js  c++  java
  • hdu 4109 Instrction Arrangement

    选拔赛的题目,关键路径

    继续延续着比赛的时候做不出,一回宿舍就1A的悲惨命运。

    这题题意还是很易懂的,不说题意了,然后一看就是一个关键路径。一个例子就是造汽车,造各种零件的时间不同,要凑齐一些零件后才能造另一些零件,问最后汽车最早什么时候造完。

    有个关键就是,如果一些零件还没有造完,而你手头上有事情可做,那么就去做,千万不要等那个零件,这样就是最优的。如果手头上没有事情可做,都是在等待的,那么只好等待了,而等待到某一个事情能开始做了,那么就做去做,就变回了上面的那种情况,但是要记得把刚才等待的时间算上去

    这个其实算是模板题,关键路径大家都学过,但是不一样都做过题,我细想才发现原来我没做过这类题只是知道原理,所以这个可能就是在比赛的时候没能做出来的原因,还是自己的错,是的,真的是自己的错。比赛时我就是按照原理去写的,但是总不对,总超时,超时我就知道是哪些写进了死循环,不会是算法的错,但是就改不出,其实当时也已经放弃了。

    回来后理清思路照着模拟一次,就1A了,但是时间不太好,140ms。后面会给出两个代码一个是自己的思路模拟出来,一个是模板

    模拟出来的代码

    /*
    1.初始化,把入度为0的点入队
    2.每个元素出队,就认为这个操作被执行,所以出队的时间就是操作时间
    3.同样地一个元素出队就进行删弧,每删一条,就判断弧头元素入度是否为0
      是的话,把它放入一个临时数组wait,不是的话不用管
    4.另外在删弧过程中,要更新弧头的可操作时间,比如当前出队元素为i,当前时间为t,弧的权是w,那么弧头j的可操作时间可能为i+w
      为什么是可能,因为一个元素可能不止受一条弧的影响,所以要找出最大的i+w,这个才是该元素的可操作时间
    5.另外注意一点,一些元素当它们同时在队列中的时候,它们的优先级相同,也就是他们的操作时间相同,所以队列中所有元素都出队的时候
      时间才能增加
    6.再说回头,在一趟出队后,会有一系列的元素进入临时数组wait,并且他们的可操作时间一定是被计算完毕的了(因为指向他们的弧都已经删除了)
      对这个数组进行降序排序,那么最后的元素就是可操作时间最早的,也就是可能最先被操作的
      我们从最后开始扫描数组,找出可以在下1秒操作的元素,直到找不到为止。而找到的元素全部入队,因为他们下一秒将被执行
      注意这里,wait数组里面如果还有元素,说明这些元素已经不受任何别的元素约束,而只是因为时间没到所以他们不能执行
      而能在下一秒执行的元素已经入队了,他们将在下1秒出队并且删弧,并且看看能不能找到一些新的元素加入wait数组
      而不是等待wait数组里面的元素被执行(为什么不利用这些等待时间去做别的事情呢?)
      另外一点,会不会在扫描wait数组的时候,一个可操作元素都没有呢?完全有可能,也就是说,这个时间我们什么都干不了,只能等待
      所以我们将时间增加,增加到wait数组最后一个元素的那个时间,那么这个元素可以从wait数组里面出来并进入队列,同样的,数组跟
      它相同的元素也可以出来,那么又变回了上面的那种情况
    8.整个算法的结束就是wait数组为空,也就是说,队列里面的元素都可以来,都企图删弧,企图把一些元素拉入wait数组,但是不成功,
      没有元素能进去,而同时队列也为空了,那么就是全部元素都处理完了
    */
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <vector>
    #include <queue>
    #include <stack>
    using namespace std;
    #define N 1010
    #define M 10010
    
    int n,m;
    int first[N];
    int in[N],out[N];
    int MAX[N];
    struct edge
    {
        int u,v,w,next;
    }e[M];
    int nume;
    
    void add(int u ,int v ,int w)
    {
        e[nume].u=u; e[nume].v=v; e[nume].w=w;
        e[nume].next=first[u]; first[u]=nume++;
    }
    
    void build()
    {
        memset(in,0,sizeof(in));
        memset(out,0,sizeof(out));
        memset(first,-1,sizeof(first));
        nume=0;
        for(int i=0; i<m; i++)
        {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            out[u]++; in[v]++;
            add(u,v,w);
        }
    }
    
    int cmp(int a ,int b)
    {
        return MAX[a] > MAX[b];
    }
    
    void solve()
    {
        int time;
        int wait[N],numw;
        queue<int>q;
    
        time=0; numw=0;
        while(!q.empty()) q.pop();
        memset(MAX,-1,sizeof(MAX));
        for(int i=0; i<n; i++) 
            if(!in[i])
                q.push(i);
        while(1)
        {
            time++; //这一批元素的操作时间
            while(!q.empty()) //同时在队列里面的元素操作时间都是相同的
            {
                int u;
                u=q.front(); q.pop();
                for(int k=first[u]; k!=-1; k=e[k].next) //删弧
                {
                    int v,w;
                    v=e[k].v; w=e[k].w;
                    in[v]--;
                    if(time+w > MAX[v]) 
                        MAX[v]=time+w; 
                    if(!in[v]) //可以进入wait数组
                        wait[numw++]=v;
                }
            }
            if(!numw) break;  //此时队列为空,wait数组也为空
            sort(wait,wait+numw,cmp); //给wait数组降序排序
            //for(int i=0; i<numw; i++) printf("%d=%d\n",wait[i],MAX[wait[i]]);
    
            int flag=0;
            while(numw>0 && MAX[wait[numw-1]] <= time+1) //从后面扫描,看有没有元素可以在下1秒执行
            {
                flag=1;
                q.push(wait[numw-1]);
                numw--;
            }
            if(!flag) //在wait数组里面一个都没有找到,那么将时间调到MAX[wait[numw-1]]的那个时间
            {
                time=MAX[wait[numw-1]];
                q.push(wait[numw-1]);
                numw--;
                while(numw>0 && MAX[wait[numw-1]] == time)
                {
                    q.push(wait[numw-1]);
                    numw--;
                }
                time--; //记得减1
            }
        }
        printf("%d\n",time);
    }
    
    int main()
    {
        while(scanf("%d%d",&n,&m)!=EOF)
        {
            build();
            solve();
        }
        return 0;
    }

    这个算是模板啦,直接从关键路径的定义出发,并且给出了最简洁的算法,其实和上面的道理是一样的,只是不知道为什么这个代码的时间更慢

    分析请移步  关键路径

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    using namespace std;
    #define N 1010
    #define M 10010
    
    int n,m;
    int first[N];
    int in[N];
    int MAX[N];
    struct edge
    {
        int u,v,w,next;
    }e[M];
    int nume;
    
    void add(int u ,int v ,int w)
    {
        e[nume].u=u; e[nume].v=v; e[nume].w=w;
        e[nume].next=first[u]; first[u]=nume++;
    }
    
    void build()
    {
        memset(in,0,sizeof(in));
        memset(first,-1,sizeof(first));
        nume=0;
        for(int i=0; i<m; i++)
        {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            in[v]++;
            add(u,v,w);
        }
    }
    
    void solve()
    {
        int T[N];  //每个点的最早完成时间
        queue<int>q;
        memset(T,-1,sizeof(T));
        while(!q.empty()) q.pop();
        for(int i=0; i<n; i++) if(!in[i])
        {
            q.push(i);
            T[i]=1;
        }
        while(!q.empty())
        {
            int u,v,w;
            u=q.front(); q.pop();
            for(int k=first[u]; k!=-1; k=e[k].next)
            {
                v=e[k].v; w=e[k].w;
                T[v] = max(T[v] , T[u]+w);
                in[v]--;
                if(!in[v]) q.push(v);
            }
        }
        int ans=-1;
        for(int i=0; i<n; i++)
            ans = max(ans , T[i]);
        printf("%d\n",ans);
    }
    
    int main()
    {
        while(scanf("%d%d",&n,&m)!=EOF)
        {
            build();
            solve();
        }
        return 0;
    }
  • 相关阅读:
    struts2基础
    hibernate框架基础
    Django的模板层
    HBuilder无法连接夜神模拟器的解决办法
    Django的视图层
    Django的路由层
    Django简介
    http协议
    web应用
    Mongodb之增删改查
  • 原文地址:https://www.cnblogs.com/scau20110726/p/2977701.html
Copyright © 2011-2022 走看看